source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/util/GSDocumentModel.java@ 24409

Last change on this file since 24409 was 24409, checked in by sjm84, 13 years ago

Added comments and fixed an error that was somehow introduced

  • Property svn:executable set to *
File size: 59.2 KB
Line 
1package org.greenstone.gsdl3.util;
2
3import java.io.BufferedWriter;
4import java.io.File;
5import java.io.FileInputStream;
6import java.io.FileOutputStream;
7import java.io.FileWriter;
8import java.nio.channels.FileChannel;
9import java.util.ArrayList;
10import java.util.HashMap;
11import java.util.Vector;
12
13import javax.xml.parsers.DocumentBuilder;
14import javax.xml.parsers.DocumentBuilderFactory;
15import javax.xml.transform.Result;
16import javax.xml.transform.Transformer;
17import javax.xml.transform.TransformerFactory;
18import javax.xml.transform.dom.DOMSource;
19import javax.xml.transform.stream.StreamResult;
20
21import org.greenstone.gsdl3.core.MessageRouter;
22import org.w3c.dom.Document;
23import org.w3c.dom.Element;
24import org.w3c.dom.Node;
25import org.w3c.dom.NodeList;
26
27public class GSDocumentModel
28{
29 //The two archive databases
30 protected static final String ARCHIVEINFSRC = "archiveinf-src";
31 protected static final String ARCHIVEINFDOC = "archiveinf-doc";
32
33 //Set operations
34 public static final int OPERATION_REPLACE = 1;
35 public static final int OPERATION_INSERT_BEFORE = 2;
36 public static final int OPERATION_INSERT_AFTER = 3;
37 public static final int OPERATION_APPEND = 4;
38
39 //Duplicate and move operations
40 public static final int OPERATION_TYPE_DOC_TO_DOC = 1;
41 public static final int OPERATION_TYPE_DOC_TO_SEC = 2;
42 public static final int OPERATION_TYPE_SEC_TO_DOC = 3;
43 public static final int OPERATION_TYPE_SEC_TO_SEC = 4;
44
45 //Error codes
46 protected static final int NO_ERROR = 0;
47 protected static final int ERROR_OID_NOT_SPECIFIED = -1;
48 protected static final int ERROR_COLLECTION_NOT_SPECIFIED = -2;
49 protected static final int ERROR_SOURCE_DOCUMENT_OR_SECTION_DOES_NOT_EXIST = -3;
50 protected static final int ERROR_DESTINATION_DOCUMENT_OR_SECTION_DOES_NOT_EXIST = -4;
51 protected static final int ERROR_DESTINATION_DOCUMENT_OR_SECTION_ALREADY_EXISTS = -5;
52 protected static final int ERROR_COULD_NOT_DUPLICATE = -6;
53 protected static final int ERROR_COULD_NOT_MOVE = -7;
54 protected static final int ERROR_DOC_XML_COULD_NOT_BE_CREATED = -8;
55 protected static final int ERROR_EXCEPTION_CREATING_DOC_XML_FILE = -9;
56 protected static final int ERROR_METADATA_NAME_NOT_SPECIFIED = -10;
57 protected static final int ERROR_METADATA_VALUE_NOT_SPECIFIED = -11;
58 protected static final int ERROR_COULD_NOT_RETRIEVE_DOC_XML = -12;
59 protected static final int ERROR_COULD_NOT_WRITE_TO_DOC_XML = -13;
60 protected static final int ERROR_COULD_NOT_RETRIEVE_SECTION = -14;
61 protected static final int ERROR_COULD_NOT_OPEN_DATABASE = -15;
62 protected static final int ERROR_DATA_NOT_FOUND_IN_DATABASE = -16;
63 protected static final int ERROR_COULD_NOT_DELETE = -16;
64 protected static final int ERROR_OID_INCORRECT_FORMAT = -17;
65 protected static final int ERROR_INVALID_MERGE = -18;
66 protected static final int ERROR_INVALID_METADATA_POSITION = -19;
67 protected static final int ERROR_INVALID_SPLIT = -20;
68 protected static final int ERROR_DESTINATION_OID_NOT_SPECIFIED = -21;
69 protected static final HashMap<Integer, String> _errorMessageMap;
70
71 static
72 {
73 //Corresponding error messages
74 HashMap<Integer, String> errorMessageMap = new HashMap<Integer, String>();
75 errorMessageMap.put(ERROR_OID_NOT_SPECIFIED, "OID not specified");
76 errorMessageMap.put(ERROR_COLLECTION_NOT_SPECIFIED, "Collection not specified");
77 errorMessageMap.put(ERROR_SOURCE_DOCUMENT_OR_SECTION_DOES_NOT_EXIST, "The specified source document or section does not exist");
78 errorMessageMap.put(ERROR_DESTINATION_DOCUMENT_OR_SECTION_DOES_NOT_EXIST, "The specified destination document or section does not exist");
79 errorMessageMap.put(ERROR_DESTINATION_DOCUMENT_OR_SECTION_ALREADY_EXISTS, "The specified destination document or section already exists");
80 errorMessageMap.put(ERROR_COULD_NOT_DUPLICATE, "There was an error duplicating document or section");
81 errorMessageMap.put(ERROR_COULD_NOT_MOVE, "There was an error moving document or section");
82 errorMessageMap.put(ERROR_DOC_XML_COULD_NOT_BE_CREATED, "The doc.xml file already exists or could not be created");
83 errorMessageMap.put(ERROR_EXCEPTION_CREATING_DOC_XML_FILE, "There was an exception while creating the doc.xml file");
84 errorMessageMap.put(ERROR_METADATA_NAME_NOT_SPECIFIED, "The name of the requested metadata was not specified");
85 errorMessageMap.put(ERROR_METADATA_VALUE_NOT_SPECIFIED, "The new value for this metadata was not specified");
86 errorMessageMap.put(ERROR_COULD_NOT_RETRIEVE_DOC_XML, "Could not retrieve the necessary doc.xml file");
87 errorMessageMap.put(ERROR_COULD_NOT_WRITE_TO_DOC_XML, "There was an error writing to the doc.xml file");
88 errorMessageMap.put(ERROR_COULD_NOT_RETRIEVE_SECTION, "There was an error retrieving the specified section from the doc.xml file");
89 errorMessageMap.put(ERROR_COULD_NOT_OPEN_DATABASE, "There was an error opening the archive database");
90 errorMessageMap.put(ERROR_DATA_NOT_FOUND_IN_DATABASE, "The specified information could not be found in the database");
91 errorMessageMap.put(ERROR_COULD_NOT_DELETE, "There was an error deleting this document");
92 errorMessageMap.put(ERROR_OID_INCORRECT_FORMAT, "The given OID was not in the correct format");
93 errorMessageMap.put(ERROR_INVALID_MERGE, "Merge can only be performed on two sections of the same level or a section and it's parent. Also the destination section cannot have any child sections");
94 errorMessageMap.put(ERROR_INVALID_METADATA_POSITION, "There is no metadata at the given position");
95 errorMessageMap.put(ERROR_INVALID_SPLIT, "A split at the given location is not possible, either the section does not have text or the split point does not exist");
96 errorMessageMap.put(ERROR_DESTINATION_OID_NOT_SPECIFIED, "The destination OID was not specified");
97 _errorMessageMap = errorMessageMap;
98 }
99
100 protected int _errorStatus = NO_ERROR;
101
102 protected String _siteHome;
103 protected Document _mainDoc;
104 protected MessageRouter _router;
105 protected HashMap<String, Document> _docCache = new HashMap<String, Document>();
106
107 public GSDocumentModel(String siteHome, Document mainDocument, MessageRouter router)
108 {
109 _siteHome = siteHome;
110 _mainDoc = mainDocument;
111 _router = router;
112 }
113
114 /**
115 * Can be used to create a document or create a section of a document
116 *
117 * @param oid
118 * is the identifier of the document/section to create.
119 * @param collection
120 * is the collection we want to create the document/section in.
121 */
122 public void documentCreate(String oid, String collection, String lang, String uid)
123 {
124 _errorStatus = NO_ERROR;
125 //If the collection is not specified then we cannot continue
126 if (collection == null || collection.equals(""))
127 {
128 _errorStatus = ERROR_COLLECTION_NOT_SPECIFIED;
129 return;
130 }
131
132 //If the document does not have an OID specified then generate one
133 if (oid == null || oid.equals(""))
134 {
135 oid = generateOID();
136 }
137 else if (archiveCheckDocumentOrSectionExists(oid, collection, lang, uid))
138 {
139 _errorStatus = ERROR_DESTINATION_DOCUMENT_OR_SECTION_ALREADY_EXISTS;
140 return;
141 }
142
143 //Check if the OID is the OID for a section
144 boolean section = false;
145 if (oid.contains("."))
146 {
147 section = true;
148 }
149
150 if (!section)
151 {
152 File newDir = new File(_siteHome + File.separatorChar + "collect" + File.separatorChar + collection + File.separatorChar + "archives" + File.separatorChar + oid);
153
154 if (!newDir.exists())
155 {
156 newDir.mkdir();
157 }
158
159 HashMap<String, ArrayList<String>> entries = new HashMap<String, ArrayList<String>>();
160 ArrayList<String> values = new ArrayList<String>();
161 values.add(oid + "/doc.xml");
162 entries.put("doc-file", values);
163
164 //Write the new entry to the archive database
165 archiveWriteEntryToDatabase(oid, collection, entries, lang, uid);
166 if (_errorStatus != NO_ERROR)
167 {
168 return;
169 }
170
171 //Create a basic doc.xml file to go in the new folder
172 documentXMLCreateDocXML(oid, collection, lang, uid);
173 }
174 else
175 {
176 documentXMLCreateSection(oid, collection, lang, uid);
177 }
178 }
179
180 /**
181 * Can be used to delete a document or section
182 *
183 * @param oid
184 * is the identifier of the document/section to delete.
185 * @param collection
186 * is the collection to delete the document/section from.
187 */
188 public void documentDelete(String oid, String collection, String lang, String uid)
189 {
190 _errorStatus = NO_ERROR;
191 if (oid == null || oid.equals(""))
192 {
193 _errorStatus = ERROR_OID_NOT_SPECIFIED;
194 return;
195 }
196 else if (collection == null || collection.equals(""))
197 {
198 _errorStatus = ERROR_COLLECTION_NOT_SPECIFIED;
199 return;
200 }
201
202 if (!archiveCheckDocumentOrSectionExists(oid, collection, lang, uid))
203 {
204 _errorStatus = ERROR_SOURCE_DOCUMENT_OR_SECTION_DOES_NOT_EXIST;
205 return;
206 }
207
208 //Check if the OID is the OID for a section
209 boolean section = false;
210 if (oid.contains("."))
211 {
212 section = true;
213 }
214
215 if (!section)
216 {
217 File dirToDelete = new File(_siteHome + File.separatorChar + "collect" + File.separatorChar + collection + File.separatorChar + "archives" + File.separatorChar + oid);
218
219 if (!dirToDelete.exists() || !dirToDelete.isDirectory() || !deleteDirectory(dirToDelete))
220 {
221 _errorStatus = ERROR_COULD_NOT_DELETE;
222 return;
223 }
224
225 //Remove the entry from the archive database
226 archiveRemoveEntryFromDatabase(oid, collection, lang, uid);
227 }
228 else
229 {
230 documentXMLDeleteSection(oid, collection, lang, uid);
231 }
232 }
233
234 /**
235 * Can be used to copy a document or section from one place to another.
236 *
237 * @param oid
238 * is the identifier of the document/section that is to be
239 * copied.
240 * @param collection
241 * is the collection the source document resides in.
242 * @param newOID
243 * is the new identifier for the document/section (it cannot
244 * already exist).
245 * @param newCollection
246 * is the collection the new document/section will be copied to.
247 * If this is null then the collection parameter will be used
248 * instead.
249 */
250 public void documentDuplicate(String oid, String collection, String newOID, String newCollection, String lang, String uid)
251 {
252 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
253 {
254 return;
255 }
256
257 //If a new collection is not specified then assume the collection of the original document
258 if (newCollection == null || newCollection.equals(""))
259 {
260 newCollection = collection;
261 }
262
263 //Generate an OID for the duplicate if we are not given one
264 if (newOID == null || newOID.equals(""))
265 {
266 _errorStatus = ERROR_DESTINATION_OID_NOT_SPECIFIED;
267 return;
268 }
269 else if (archiveCheckDocumentOrSectionExists(newOID, newCollection, lang, uid))
270 {
271 _errorStatus = ERROR_DESTINATION_DOCUMENT_OR_SECTION_ALREADY_EXISTS;
272 return;
273 }
274
275 //Check what operation we are performing
276 int op = getOperation(oid, newOID);
277
278 boolean requiresDatabaseEntry = false;
279 switch (op)
280 {
281 case OPERATION_TYPE_DOC_TO_DOC:
282 {
283 String archiveDir = archiveGetDocumentFilePath(oid, collection, lang, uid);
284 if (_errorStatus != NO_ERROR)
285 {
286 return;
287 }
288
289 //Remove doc.xml from the file name
290 archiveDir = archiveDir.substring(0, archiveDir.lastIndexOf(File.separator));
291 File dirToDuplicate = new File(archiveDir);
292
293 //This is possibly not the best way to name the new directory
294 File newDir = new File(archiveDir.substring(0, archiveDir.lastIndexOf(File.separator) + File.separator.length()) + newOID);
295
296 if (dirToDuplicate.exists() && dirToDuplicate.isDirectory() && !newDir.exists())
297 {
298 if (!copyDirectory(dirToDuplicate, newDir))
299 {
300 _errorStatus = ERROR_COULD_NOT_DUPLICATE;
301 return;
302 }
303 }
304 requiresDatabaseEntry = true;
305 break;
306 }
307 case OPERATION_TYPE_DOC_TO_SEC:
308 {
309 Document originalDocument = getDocXML(oid, collection, lang, uid);
310 Element originalSection = getTopLevelSectionElement(originalDocument);
311
312 documentXMLCreateSection(newOID, newCollection, lang, uid);
313 if (_errorStatus != NO_ERROR)
314 {
315 return;
316 }
317
318 documentXMLSetSection(newOID, newCollection, originalSection, OPERATION_REPLACE, lang, uid);
319 break;
320 }
321 case OPERATION_TYPE_SEC_TO_DOC:
322 {
323 Document originalDocument = getDocXML(oid, collection, lang, uid);
324 Element originalSection = getSectionBySectionNumber(originalDocument, getSectionFromOID(oid));
325
326 documentCreate(newOID, newCollection, lang, uid);
327 if (_errorStatus != NO_ERROR)
328 {
329 return;
330 }
331
332 documentXMLCreateSection(newOID, newCollection, lang, uid);
333 if (_errorStatus != NO_ERROR)
334 {
335 return;
336 }
337
338 documentXMLSetSection(newOID, newCollection, originalSection, OPERATION_REPLACE, lang, uid);
339
340 requiresDatabaseEntry = true;
341 break;
342 }
343 case OPERATION_TYPE_SEC_TO_SEC:
344 {
345 Document originalDocument = getDocXML(oid, collection, lang, uid);
346 Element originalSection = getSectionBySectionNumber(originalDocument, getSectionFromOID(oid));
347
348 documentXMLCreateSection(newOID, newCollection, lang, uid);
349 if (_errorStatus != NO_ERROR)
350 {
351 return;
352 }
353
354 documentXMLSetSection(newOID, newCollection, originalSection, OPERATION_REPLACE, lang, uid);
355 break;
356 }
357 }
358
359 if (requiresDatabaseEntry)
360 {
361 HashMap<String, ArrayList<String>> entries = new HashMap<String, ArrayList<String>>();
362 ArrayList<String> values = new ArrayList<String>();
363 values.add(newOID + "/doc.xml");
364 entries.put("doc-file", values);
365
366 //Write the new entry to the archive database
367 archiveWriteEntryToDatabase(newOID, newCollection, entries, lang, uid);
368 }
369 }
370
371 /**
372 * Can be used to acquire information about a given document or section.
373 *
374 * @param oid
375 * is the identifier of the document or section.
376 * @param collection
377 * is the collection the document or section resides in.
378 * @param requestedInfo
379 * is an array containing the various requests.
380 * @return This returns an array containing the requested information.
381 */
382 public String[] documentGetInformation(String oid, String collection, String[] requestedInfo, String lang, String uid)
383 {
384 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
385 {
386 return null;
387 }
388
389 for (int j = 0; j < requestedInfo.length; j++)
390 {
391 String currentRequest = requestedInfo[j];
392 //TODO: Decide what info requests are valid (e.g. number of sections etc.)
393 //-How many child/sibling sections
394 //-Metadata keys
395 }
396 //TODO: Implement
397 return null;
398 }
399
400 /**
401 * Can be used to move a document or section from one place to another.
402 *
403 * @param oid
404 * is the identifier of the document/section to move.
405 * @param collection
406 * is the collection the source document resides in.
407 * @param newOID
408 * is the new identifer for the moved document.
409 * @param newCollection
410 * is the collection the new document/section will be moved to.
411 * If this is null then the collection parameter will be used
412 * instead.
413 */
414 public void documentMove(String oid, String collection, String newOID, String newCollection, String lang, String uid)
415 {
416 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
417 {
418 return;
419 }
420
421 documentDuplicate(oid, collection, newOID, newCollection, lang, uid);
422 if (_errorStatus != NO_ERROR)
423 {
424 return;
425 }
426
427 documentDelete(oid, collection, lang, uid);
428 }
429
430 /**
431 * Can be used to merge two parts of a document together. The sections must
432 * be in the same document at the same level (e.g. D11.1.2 and D11.1.3) or a
433 * section and it's parent (e.g. D11.1.2 and D11.1). Also, the destination
434 * section cannot have any child sections.
435 *
436 * @param oid
437 * the identifier of the section that is to be merged.
438 * @param collection
439 * the collection the section resides in.
440 * @param mergeOID
441 * the identifier of the section that the source section will be
442 * merged into.
443 */
444 public void documentMerge(String oid, String collection, String mergeOID, String lang, String uid)
445 {
446 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
447 {
448 return;
449 }
450
451 if ((_errorStatus = checkOIDandCollection(mergeOID, collection, lang, uid)) != NO_ERROR)
452 {
453 return;
454 }
455
456 int op = getOperation(oid, mergeOID);
457 if (op != OPERATION_TYPE_SEC_TO_SEC && op != OPERATION_TYPE_SEC_TO_DOC) //We allow SEC_TO_DOC in the case that someone wants to merge D11.1 with D11 (for example)
458 {
459 _errorStatus = ERROR_INVALID_MERGE;
460 return;
461 }
462
463 String[] sourceLevels = oid.split("\\.");
464 String[] destinationLevels = mergeOID.split("\\.");
465
466 if (destinationLevels.length > sourceLevels.length)
467 {
468 _errorStatus = ERROR_INVALID_MERGE;
469 return;
470 }
471
472 for (int i = 0; i < sourceLevels.length - 1; i++)
473 {
474 if (i >= destinationLevels.length || !sourceLevels[i].equals(destinationLevels[i]))
475 {
476 _errorStatus = ERROR_INVALID_MERGE;
477 return;
478 }
479 }
480
481 Document docXML = getDocXML(oid, collection, lang, uid);
482 if (docXML == null)
483 {
484 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
485 return;
486 }
487
488 Element sourceSection = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
489 Element destinationSection = getSectionBySectionNumber(docXML, getSectionFromOID(mergeOID));
490
491 //Make sure the destination Section does not have any child Sections.
492 NodeList childSections = GSXML.getChildrenByTagName(destinationSection, GSXML.DOCXML_SECTION_ELEM);
493 if (childSections.getLength() != 0 && sourceLevels.length == destinationLevels.length)
494 {
495 _errorStatus = ERROR_INVALID_MERGE;
496 return;
497 }
498
499 //Get the children of the destination section so we can copy them to the source section before we overwrite the destination
500 NodeList childrenToKeep = destinationSection.getChildNodes();
501 ArrayList<Node> childList = new ArrayList<Node>();
502 for (int i = 0; i < childrenToKeep.getLength(); i++)
503 {
504 //Need to put these in a list to make them easier to loop through as using a NodeList is messy
505 childList.add(childrenToKeep.item(i));
506 }
507
508 //for(int i = 0; i < childrenToKeep.getLength(); i++)
509 for (int i = 0; i < childList.size(); i++)
510 {
511 Node currentChild = childList.get(i);
512 //If the child is not a <Content> node then add it to source section
513 if (!currentChild.getNodeName().equals(GSXML.DOCXML_CONTENT_ELEM))
514 {
515 sourceSection.appendChild(currentChild);
516 continue;
517 }
518
519 //Get the destination Section's Content node's text node, if it's empty then we don't need to worry about appending it
520 Node destinationTextNode = currentChild.getFirstChild();
521 if (destinationTextNode == null || destinationTextNode.getNodeValue() == null || destinationTextNode.getNodeValue().equals(""))
522 {
523 continue;
524 }
525
526 //If the source Section does not have a content then directly append the destination content
527 Element sourceContent = (Element) GSXML.getChildByTagName(sourceSection, GSXML.DOCXML_CONTENT_ELEM);
528 if (sourceContent == null)
529 {
530 sourceSection.appendChild(currentChild);
531 continue;
532 }
533
534 //If the source Section's Content is empty then again we can directly append the destination content
535 Node sourceTextNode = sourceContent.getFirstChild();
536 if (sourceTextNode == null || sourceTextNode.getNodeValue() == null || sourceTextNode.getNodeValue().equals(""))
537 {
538 sourceSection.appendChild(currentChild);
539 continue;
540 }
541
542 //Otherwise, set the new content to be destination + source text in that order.
543 sourceTextNode.setNodeValue(destinationTextNode.getNodeValue() + " " + sourceTextNode.getNodeValue());
544 }
545
546 documentXMLSetSection(mergeOID, collection, sourceSection, OPERATION_REPLACE, lang, uid);
547 if (_errorStatus != NO_ERROR)
548 {
549 return;
550 }
551
552 documentXMLDeleteSection(oid, collection, lang, uid);
553 }
554
555 /**
556 * Can be used to split a section into two sections (e.g. D11.2.1 will
557 * become D11.2.1 and D11.2.2). Any child section will belong to the second
558 * section (D11.2.2 in the example).
559 *
560 * @param oid
561 * is the identifer of the section to be split.
562 * @param collection
563 * is the collection the section resides in.
564 * @param splitPoint
565 * is the point in the text we want to split at.
566 */
567 public void documentSplit(String oid, String collection, int splitPoint, String lang, String uid)
568 {
569 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
570 {
571 return;
572 }
573
574 Document docXML = getDocXML(oid, collection, lang, uid);
575 if (docXML == null)
576 {
577 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
578 return;
579 }
580
581 Element sectionToSplit = null;
582 if (!oid.contains("."))
583 {
584 sectionToSplit = getTopLevelSectionElement(docXML);
585 }
586 else
587 {
588 sectionToSplit = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
589 }
590
591 Element content = (Element) GSXML.getChildByTagName(sectionToSplit, GSXML.DOCXML_CONTENT_ELEM);
592 if (content == null)
593 {
594 _errorStatus = ERROR_INVALID_SPLIT;
595 return;
596 }
597
598 Node textNode = content.getFirstChild();
599 if (textNode == null)
600 {
601 _errorStatus = ERROR_INVALID_SPLIT;
602 return;
603 }
604
605 String text = textNode.getNodeValue();
606 if (splitPoint > text.length() - 2 || splitPoint < 1) //-1 would be the index of the last character, so the last valid split point is -2
607 {
608 _errorStatus = ERROR_INVALID_SPLIT;
609 return;
610 }
611
612 String firstPart = text.substring(0, splitPoint);
613 String secondPart = text.substring(splitPoint);
614
615 Element newSection = docXML.createElement(GSXML.DOCXML_SECTION_ELEM);
616 Element newContent = docXML.createElement(GSXML.DOCXML_CONTENT_ELEM);
617 Node newTextNode = docXML.createTextNode(firstPart);
618 newContent.appendChild(newTextNode);
619 newSection.appendChild(newContent);
620
621 documentXMLSetSection(oid, collection, newSection, OPERATION_INSERT_BEFORE, lang, uid);
622 if (_errorStatus != NO_ERROR)
623 {
624 return;
625 }
626 textNode.setNodeValue(secondPart);
627
628 //Write the new change back into the file
629 if (!writeXMLFile(docXML, oid, collection, lang, uid))
630 {
631 _errorStatus = ERROR_COULD_NOT_WRITE_TO_DOC_XML;
632 }
633 }
634
635 /**
636 * Creates a basic doc.xml file with minimal contents.
637 *
638 * @param oid
639 * is the identifier of the document to be created.
640 * @param collection
641 * is the collection the new document will reside in.
642 */
643 public void documentXMLCreateDocXML(String oid, String collection, String lang, String uid)
644 {
645 _errorStatus = NO_ERROR;
646 try
647 {
648 Document docXML = null;
649
650 String filePath = archiveGetDocumentFilePath(oid, collection, lang, uid);
651 File docFile = new File(filePath);
652 if (!docFile.exists() && !docFile.createNewFile())
653 {
654 _errorStatus = ERROR_DOC_XML_COULD_NOT_BE_CREATED;
655 return;
656 }
657
658 BufferedWriter bw = new BufferedWriter(new FileWriter(docFile));
659 bw.write("<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n");
660 bw.write("<!DOCTYPE Archive SYSTEM \"http://greenstone.org/dtd/Archive/1.0/Archive.dtd\">\n");
661 bw.write("<Archive>\n");
662 bw.write("</Archive>\n");
663 bw.close();
664
665 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
666 DocumentBuilder db = dbf.newDocumentBuilder();
667 docXML = db.parse(docFile);
668
669 _docCache.put(oid + "__" + collection, docXML);
670 }
671 catch (Exception ex)
672 {
673 ex.printStackTrace();
674 _errorStatus = ERROR_EXCEPTION_CREATING_DOC_XML_FILE;
675 return;
676 }
677 }
678
679 /**
680 * Gets a metadata value from a document or section.
681 *
682 * @param oid
683 * is the identifier of the section or document to get metadata
684 * from.
685 * @param collection
686 * is the collection the section or document resides in.
687 * @param metadataName
688 * is the name of metadata to retrieve
689 * @return an array of metadata elements containing the resquested metadata
690 */
691 public ArrayList<Element> documentXMLGetMetadata(String oid, String collection, String metadataName, String lang, String uid)
692 {
693 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
694 {
695 return null;
696 }
697 else if (metadataName == null || metadataName.equals(""))
698 {
699 _errorStatus = ERROR_METADATA_NAME_NOT_SPECIFIED;
700 return null;
701 }
702
703 Document docXML = getDocXML(oid, collection, lang, uid);
704 if (docXML == null)
705 {
706 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
707 return null;
708 }
709
710 return getMetadataElementsFromSection(docXML, oid, metadataName);
711 }
712
713 /**
714 *
715 * @param oid
716 * is the identifier of the document or section that is to have
717 * it's metadata set.
718 * @param collection
719 * is the collection the document/section resides in.
720 * @param metadataName
721 * is the name of the metadata value that is to be set.
722 * @param newMetadataValue
723 * is the new value of the metadata.
724 * @param position
725 * specifies the position of the value to set.
726 * @param operation
727 * can be one of OPERATION_REPLACE, OPERATION_INSERT_BEFORE,
728 * OPERATION_INSERT_AFTER or OPERATION_APPEND.
729 */
730 public void documentXMLSetMetadata(String oid, String collection, String metadataName, String newMetadataValue, int position, int operation, String lang, String uid)
731 {
732 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
733 {
734 return;
735 }
736 else if (metadataName == null || metadataName.equals(""))
737 {
738 _errorStatus = ERROR_METADATA_NAME_NOT_SPECIFIED;
739 return;
740 }
741 else if (newMetadataValue == null || newMetadataValue.equals(""))
742 {
743 _errorStatus = ERROR_METADATA_VALUE_NOT_SPECIFIED;
744 return;
745 }
746
747 Document docXML = getDocXML(oid, collection, lang, uid);
748 if (docXML == null)
749 {
750 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
751 return;
752 }
753
754 ArrayList<Element> metadataElems = getMetadataElementsFromSection(docXML, oid, metadataName);
755
756 if (operation != OPERATION_APPEND && metadataElems.get(position) == null)
757 {
758 _errorStatus = ERROR_INVALID_METADATA_POSITION;
759 return;
760 }
761
762 if (operation == OPERATION_REPLACE)
763 {
764 metadataElems.get(position).setNodeValue(newMetadataValue);
765 }
766 else if (operation == OPERATION_INSERT_BEFORE)
767 {
768 Element newMetadata = createElementWithValue(docXML, GSXML.DOCXML_METADATA_ELEM, metadataName, newMetadataValue);
769 Element existingMetadata = metadataElems.get(position);
770
771 existingMetadata.getParentNode().insertBefore(newMetadata, existingMetadata);
772 }
773 else if (operation == OPERATION_INSERT_AFTER)
774 {
775 Element newMetadata = createElementWithValue(docXML, GSXML.DOCXML_METADATA_ELEM, metadataName, newMetadataValue);
776 Element existingMetadata = metadataElems.get(position + 1);
777
778 if (existingMetadata != null)
779 {
780 existingMetadata.getParentNode().insertBefore(newMetadata, existingMetadata);
781 }
782 else
783 {
784 existingMetadata = metadataElems.get(position);
785 existingMetadata.getParentNode().appendChild(newMetadata);
786 }
787 }
788 else
789 {
790 Element section = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
791 Element description = (Element) GSXML.getChildByTagName(section, GSXML.DOCXML_DESCRIPTION_ELEM);
792 if (description == null)
793 {
794 description = docXML.createElement(GSXML.DOCXML_DESCRIPTION_ELEM);
795 section.appendChild(description);
796 }
797 Element newMetadata = createElementWithValue(docXML, GSXML.DOCXML_METADATA_ELEM, metadataName, newMetadataValue);
798 description.appendChild(newMetadata);
799 }
800
801 //Write the new change back into the file
802 if (!writeXMLFile(docXML, oid, collection, lang, uid))
803 {
804 _errorStatus = ERROR_COULD_NOT_WRITE_TO_DOC_XML;
805 }
806 }
807
808 /**
809 * Can be used to delete metadata at a specific position in a document or
810 * section (such as the third author of a document).
811 *
812 * @param oid
813 * is the identifier of the document/section to delete metadata
814 * from.
815 * @param collection
816 * is the collection the document resides in.
817 * @param metadataName
818 * is the name of the metadata that is to have an item deleted.
819 * @param position
820 * is position of the item that is to be deleted.
821 */
822 public void documentXMLDeleteMetadata(String oid, String collection, String metadataName, int position, String lang, String uid)
823 {
824 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
825 {
826 return;
827 }
828 else if (metadataName == null || metadataName.equals(""))
829 {
830 _errorStatus = ERROR_METADATA_NAME_NOT_SPECIFIED;
831 return;
832 }
833
834 Document docXML = getDocXML(oid, collection, lang, uid);
835 if (docXML == null)
836 {
837 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
838 return;
839 }
840
841 ArrayList<Element> metadataElems = getMetadataElementsFromSection(docXML, oid, metadataName);
842
843 if (metadataElems.get(position) != null)
844 {
845 metadataElems.get(position).getParentNode().removeChild(metadataElems.get(position));
846 }
847 }
848
849 /**
850 * Can be used to delete all the metadata with a specific name from a
851 * document or section (e.g. all of the authors).
852 *
853 * @param oid
854 * is the identifier of the document or section to delete the
855 * metadata from.
856 * @param collection
857 * is the collection the document resides in.
858 * @param metadataName
859 * is the name of the metadata to delete.
860 */
861 public void documentXMLDeleteMetadata(String oid, String collection, String metadataName, String lang, String uid)
862 {
863 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
864 {
865 return;
866 }
867 else if (metadataName == null || metadataName.equals(""))
868 {
869 _errorStatus = ERROR_METADATA_NAME_NOT_SPECIFIED;
870 return;
871 }
872
873 Document docXML = getDocXML(oid, collection, lang, uid);
874 if (docXML == null)
875 {
876 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
877 return;
878 }
879
880 ArrayList<Element> metadataElems = getMetadataElementsFromSection(docXML, oid, metadataName);
881
882 for (Element elem : metadataElems)
883 {
884 elem.getParentNode().removeChild(elem);
885 }
886 }
887
888 /**
889 * Can be used to replace a specific metadata item of a given name, given
890 * it's value.
891 *
892 * @param oid
893 * is the document/section of the metadata that is to be
894 * replaced.
895 * @param collection
896 * is the collection the document resides in.
897 * @param metadataName
898 * is the name of the metadata to be replaced.
899 * @param oldMetadataValue
900 * is the old value of the metadata (the value that will be
901 * replaced).
902 * @param newMetadataValue
903 * is the new value of the metadata that will replace the old
904 * value.
905 */
906 public void documentXMLReplaceMetadata(String oid, String collection, String metadataName, String oldMetadataValue, String newMetadataValue, String lang, String uid)
907 {
908 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
909 {
910 return;
911 }
912 else if (metadataName == null || metadataName.equals(""))
913 {
914 _errorStatus = ERROR_METADATA_NAME_NOT_SPECIFIED;
915 return;
916 }
917 else if (newMetadataValue == null || newMetadataValue.equals(""))
918 {
919 _errorStatus = ERROR_METADATA_VALUE_NOT_SPECIFIED;
920 return;
921 }
922 else if (oldMetadataValue == null || oldMetadataValue.equals(""))
923 {
924 _errorStatus = ERROR_METADATA_VALUE_NOT_SPECIFIED;
925 return;
926 }
927
928 Document docXML = getDocXML(oid, collection, lang, uid);
929 if (docXML == null)
930 {
931 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
932 return;
933 }
934
935 ArrayList<Element> metadataElems = getMetadataElementsFromSection(docXML, oid, metadataName);
936
937 for (Element elem : metadataElems)
938 {
939 Node textNode = elem.getFirstChild();
940
941 if (textNode != null && textNode.getNodeValue().equals(oldMetadataValue))
942 {
943 textNode.setNodeValue(newMetadataValue);
944 }
945 }
946
947 //Write the new change back into the file
948 if (!writeXMLFile(docXML, oid, collection, lang, uid))
949 {
950 _errorStatus = ERROR_COULD_NOT_WRITE_TO_DOC_XML;
951 }
952 }
953
954 /**
955 * Can be used to create a blank section.
956 *
957 * @param oid
958 * is the identifier of the section to be created.
959 * @param collection
960 * is the collection the document resides in.
961 */
962 public void documentXMLCreateSection(String oid, String collection, String lang, String uid)
963 {
964 _errorStatus = NO_ERROR;
965 if (oid == null || oid.equals(""))
966 {
967 _errorStatus = ERROR_OID_NOT_SPECIFIED;
968 return;
969 }
970 else if (collection == null || collection.equals(""))
971 {
972 _errorStatus = ERROR_COLLECTION_NOT_SPECIFIED;
973 return;
974 }
975
976 if (oid.contains(".") && !archiveCheckDocumentOrSectionExists(oid.substring(0, oid.indexOf(".")), collection, lang, uid))
977 {
978 documentCreate(oid.substring(0, oid.indexOf(".")), collection, lang, uid);
979 if (_errorStatus != NO_ERROR)
980 {
981 return;
982 }
983 }
984
985 Document docXML = getDocXML(oid, collection, lang, uid);
986 if (docXML == null)
987 {
988 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
989 return;
990 }
991
992 Element topLevel = docXML.getDocumentElement();
993 if (!oid.contains("."))
994 {
995 if (GSXML.getChildByTagName(topLevel, GSXML.DOCXML_SECTION_ELEM) == null)
996 {
997 Element newSection = docXML.createElement(GSXML.DOCXML_SECTION_ELEM);
998 topLevel.appendChild(newSection);
999 }
1000 }
1001 else
1002 {
1003 int[] intLevels = null;
1004 try
1005 {
1006 intLevels = oidToSectionNumberArray(oid);
1007 }
1008 catch (Exception ex)
1009 {
1010 _errorStatus = ERROR_OID_INCORRECT_FORMAT;
1011 return;
1012 }
1013
1014 Element current = (Element) GSXML.getChildByTagName(topLevel, GSXML.DOCXML_SECTION_ELEM);
1015 if (current == null)
1016 {
1017 Element topLevelSection = docXML.createElement(GSXML.DOCXML_SECTION_ELEM);
1018 topLevel.appendChild(topLevelSection);
1019 current = topLevelSection;
1020 }
1021
1022 for (int currentLevelValue : intLevels)
1023 {
1024 NodeList sections = GSXML.getChildrenByTagName(current, GSXML.DOCXML_SECTION_ELEM);
1025
1026 if (sections.item(currentLevelValue - 1) == null)
1027 {
1028 Element latest = null;
1029 for (int j = 0; j < currentLevelValue - sections.getLength(); j++)
1030 {
1031 Element blankSection = docXML.createElement(GSXML.DOCXML_SECTION_ELEM);
1032 current.appendChild(blankSection);
1033 latest = blankSection;
1034 }
1035 current = latest;
1036 }
1037 else
1038 {
1039 current = (Element) sections.item(currentLevelValue - 1);
1040 }
1041 }
1042 }
1043
1044 //Write the new change back into the file
1045 if (!writeXMLFile(docXML, oid, collection, lang, uid))
1046 {
1047 _errorStatus = ERROR_COULD_NOT_WRITE_TO_DOC_XML;
1048 }
1049 }
1050
1051 /**
1052 * Can be used to delete an entire section.
1053 *
1054 * @param oid
1055 * is the identifier of the section to be deleted.
1056 * @param collection
1057 * is the collection the document resides in.
1058 */
1059 public void documentXMLDeleteSection(String oid, String collection, String lang, String uid)
1060 {
1061 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
1062 {
1063 return;
1064 }
1065
1066 Document docXML = getDocXML(oid, collection, lang, uid);
1067 if (docXML == null)
1068 {
1069 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
1070 return;
1071 }
1072
1073 Element section = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
1074 if (section == null)
1075 {
1076 _errorStatus = ERROR_COULD_NOT_DELETE;
1077 return;
1078 }
1079
1080 section.getParentNode().removeChild(section);
1081
1082 //Write the new change back into the file
1083 if (!writeXMLFile(docXML, oid, collection, lang, uid))
1084 {
1085 _errorStatus = ERROR_COULD_NOT_WRITE_TO_DOC_XML;
1086 }
1087 }
1088
1089 /**
1090 * Can be used to get a section from a document.
1091 *
1092 * @param oid
1093 * is the identifier of the section to get.
1094 * @param collection
1095 * is the collection the document resides in.
1096 * @return the requested section.
1097 */
1098 public Element documentXMLGetSection(String oid, String collection, String lang, String uid)
1099 {
1100 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
1101 {
1102 return null;
1103 }
1104
1105 Document docXML = getDocXML(oid, collection, lang, uid);
1106 if (docXML == null)
1107 {
1108 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
1109 return null;
1110 }
1111
1112 Element section = null;
1113 if (!oid.contains("."))
1114 {
1115 section = getTopLevelSectionElement(docXML);
1116 }
1117 else
1118 {
1119 section = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
1120 }
1121
1122 if (section == null)
1123 {
1124 _errorStatus = ERROR_COULD_NOT_RETRIEVE_SECTION;
1125 return null;
1126 }
1127
1128 return section;
1129 }
1130
1131 /**
1132 * Can be used to set an OID to the given section element.
1133 *
1134 * @param oid
1135 * is the identifier of the section to be set.
1136 * @param collection
1137 * is the collection the section will reside in.
1138 * @param newSection
1139 * is the new section element.
1140 * @param operation
1141 * can be one of OPERATION_REPLACE, OPERATION_INSERT_BEFORE,
1142 * OPERATION_INSERT_AFTER or OPERATION_APPEND.
1143 */
1144 public void documentXMLSetSection(String oid, String collection, Element newSection, int operation, String lang, String uid)
1145 {
1146 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
1147 {
1148 return;
1149 }
1150
1151 Document docXML = getDocXML(oid, collection, lang, uid);
1152 if (docXML == null)
1153 {
1154 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
1155 return;
1156 }
1157
1158 Element existingSection = null;
1159 if (!oid.contains("."))
1160 {
1161 existingSection = getTopLevelSectionElement(docXML);
1162 }
1163 else
1164 {
1165 existingSection = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
1166 }
1167
1168 if (existingSection == null)
1169 {
1170 _errorStatus = ERROR_COULD_NOT_RETRIEVE_SECTION;
1171 return;
1172 }
1173
1174 Element importedSection = (Element) docXML.importNode(newSection, true);
1175
1176 if (operation == OPERATION_APPEND)
1177 {
1178 existingSection.appendChild(importedSection);
1179 }
1180 else
1181 {
1182 Node sectionParent = existingSection.getParentNode();
1183
1184 //Remove the attributes that are only there to help us find the section
1185 importedSection.removeAttribute(GSXML.NODE_ID_ATT);
1186 importedSection.removeAttribute(GSXML.COLLECTION_ATT);
1187
1188 if (operation == OPERATION_INSERT_BEFORE || operation == OPERATION_REPLACE)
1189 {
1190 sectionParent.insertBefore(importedSection, existingSection);
1191 }
1192 else if (operation == OPERATION_INSERT_AFTER)
1193 {
1194 Element sibling = (Element) existingSection.getNextSibling();
1195 if (sibling == null)
1196 {
1197 sectionParent.insertBefore(importedSection, sibling);
1198 }
1199 else
1200 {
1201 sectionParent.appendChild(importedSection);
1202 }
1203 }
1204
1205 if (operation == OPERATION_REPLACE)
1206 {
1207 sectionParent.removeChild(existingSection);
1208 }
1209 }
1210
1211 //Write the new change back into the file
1212 if (!writeXMLFile(docXML, oid, collection, lang, uid))
1213 {
1214 _errorStatus = ERROR_COULD_NOT_WRITE_TO_DOC_XML;
1215 return;
1216 }
1217 }
1218
1219 /**
1220 * Gets the text of a given section as a string.
1221 *
1222 * @param oid
1223 * is the identifier of the section to get the text from.
1224 * @param collection
1225 * is the collection the document resides in.
1226 * @return the text from the section.
1227 */
1228 public String documentXMLGetText(String oid, String collection, String lang, String uid)
1229 {
1230 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
1231 {
1232 return null;
1233 }
1234
1235 Document docXML = getDocXML(oid, collection, lang, uid);
1236 if (docXML == null)
1237 {
1238 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
1239 return null;
1240 }
1241
1242 Element section = null;
1243 if (!oid.contains("."))
1244 {
1245 section = getTopLevelSectionElement(docXML);
1246 }
1247 else
1248 {
1249 section = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
1250 }
1251
1252 if (section == null)
1253 {
1254 _errorStatus = ERROR_COULD_NOT_RETRIEVE_SECTION;
1255 return null;
1256 }
1257
1258 Element contentNode = (Element) GSXML.getChildByTagName(section, GSXML.DOCXML_CONTENT_ELEM);
1259 if (contentNode == null)
1260 {
1261 return null;
1262 }
1263
1264 Node textNode = contentNode.getFirstChild();
1265 if (textNode == null)
1266 {
1267 return null;
1268 }
1269
1270 return textNode.getNodeValue();
1271 }
1272
1273 /**
1274 * Sets the text of a given section using an element.
1275 *
1276 * @param oid
1277 * is the identifier of the section to set the text of.
1278 * @param collection
1279 * is the collection the document resides in.
1280 * @param newContent
1281 * is the new content element for the section.
1282 */
1283 public void documentXMLSetText(String oid, String collection, Element newContent, String lang, String uid)
1284 {
1285 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
1286 {
1287 return;
1288 }
1289
1290 Document docXML = getDocXML(oid, collection, lang, uid);
1291 if (docXML == null)
1292 {
1293 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
1294 return;
1295 }
1296
1297 Element section = null;
1298 if (!oid.contains("."))
1299 {
1300 section = getTopLevelSectionElement(docXML);
1301 }
1302 else
1303 {
1304 section = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
1305 }
1306
1307 if (section == null)
1308 {
1309 _errorStatus = ERROR_COULD_NOT_RETRIEVE_SECTION;
1310 return;
1311 }
1312
1313 Element existingContent = (Element) GSXML.getChildByTagName(section, GSXML.DOCXML_CONTENT_ELEM);
1314
1315 //Remove the attributes that are only there to help us find the content
1316 newContent.removeAttribute(GSXML.NODE_ID_ATT);
1317 newContent.removeAttribute(GSXML.COLLECTION_ATT);
1318
1319 Element importedContent = (Element) docXML.importNode(newContent, true);
1320 //If the current section does not have content then just add it, otherwise replace the existing one
1321 if (existingContent == null)
1322 {
1323 section.appendChild(importedContent);
1324 }
1325 else
1326 {
1327 Node contentParent = existingContent.getParentNode();
1328
1329 //Replace the old node in the document tree
1330 contentParent.insertBefore(importedContent, existingContent);
1331 contentParent.removeChild(existingContent);
1332 }
1333
1334 //Write the new change back into the file
1335 if (!writeXMLFile(docXML, oid, collection, lang, uid))
1336 {
1337 _errorStatus = ERROR_COULD_NOT_WRITE_TO_DOC_XML;
1338 return;
1339 }
1340 }
1341
1342 /**
1343 * Sets the text of a given section using a string.
1344 *
1345 * @param oid
1346 * is the identifier of the section to set the text of.
1347 * @param collection
1348 * is the collection the document resides in.
1349 * @param newContent
1350 * is the new text for the section.
1351 */
1352 public void documentXMLSetText(String oid, String collection, String newContent, String lang, String uid)
1353 {
1354 if ((_errorStatus = checkOIDandCollection(oid, collection, lang, uid)) != NO_ERROR)
1355 {
1356 return;
1357 }
1358
1359 Document docXML = getDocXML(oid, collection, lang, uid);
1360 if (docXML == null)
1361 {
1362 _errorStatus = ERROR_COULD_NOT_RETRIEVE_DOC_XML;
1363 return;
1364 }
1365
1366 Element section = null;
1367 if (!oid.contains("."))
1368 {
1369 section = getTopLevelSectionElement(docXML);
1370 }
1371 else
1372 {
1373 section = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
1374 }
1375
1376 if (section == null)
1377 {
1378 _errorStatus = ERROR_COULD_NOT_RETRIEVE_SECTION;
1379 return;
1380 }
1381
1382 Element existingContent = (Element) GSXML.getChildByTagName(section, GSXML.DOCXML_CONTENT_ELEM);
1383
1384 //If the current section does not have content then just add it, otherwise replace the existing one
1385 if (existingContent == null)
1386 {
1387 Element newContentElem = docXML.createElement(GSXML.DOCXML_CONTENT_ELEM);
1388 Node textNode = docXML.createTextNode(newContent);
1389 newContentElem.appendChild(textNode);
1390 }
1391 else
1392 {
1393 Node textNode = existingContent.getFirstChild();
1394 if (textNode != null)
1395 {
1396 textNode.setNodeValue(newContent);
1397 }
1398 else
1399 {
1400 existingContent.appendChild(docXML.createTextNode(newContent));
1401 }
1402 }
1403
1404 //Write the new change back into the file
1405 if (!writeXMLFile(docXML, oid, collection, lang, uid))
1406 {
1407 _errorStatus = ERROR_COULD_NOT_WRITE_TO_DOC_XML;
1408 return;
1409 }
1410 }
1411
1412 /**
1413 * Can be used to get the file path of the doc.xml file containing the given
1414 * OID.
1415 *
1416 * @param oid
1417 * is the identifier of the document/section to get the doc.xml
1418 * of.
1419 * @param collection
1420 * is the collection the document resides in.
1421 * @return the file path to the doc.xml file.
1422 */
1423 public String archiveGetDocumentFilePath(String oid, String collection, String lang, String uid)
1424 {
1425 _errorStatus = NO_ERROR;
1426
1427 if (oid.contains("."))
1428 {
1429 oid = oid.substring(0, oid.indexOf("."));
1430 }
1431
1432 String assocFilePath = getDocFilePathFromDatabase(oid, collection, lang, uid);
1433 if (assocFilePath == null)
1434 {
1435 _errorStatus = ERROR_DATA_NOT_FOUND_IN_DATABASE;
1436 return null;
1437 }
1438
1439 if (File.separator.equals("\\"))
1440 {
1441 assocFilePath = assocFilePath.replace("/", "\\");
1442 }
1443
1444 String docFilePath = _siteHome + File.separatorChar + "collect" + File.separatorChar + collection + File.separatorChar + "archives" + File.separatorChar + assocFilePath;
1445 return docFilePath;
1446 }
1447
1448 /**
1449 * Can be used to find the document that a specific source file is used in.
1450 *
1451 * @param srcFile
1452 * is the name of the source file.
1453 * @param collection
1454 * is the collection the source file resides in.
1455 * @return the OID of the document that the source file is used in.
1456 */
1457 public String archiveGetSourceFileOID(String srcFile, String collection, String lang, String uid)
1458 {
1459 _errorStatus = NO_ERROR;
1460 SimpleCollectionDatabase coll_db = openDatabase(collection, ARCHIVEINFSRC, SimpleCollectionDatabase.READ, lang, uid);
1461 if (coll_db == null)
1462 {
1463 _errorStatus = ERROR_COULD_NOT_OPEN_DATABASE;
1464 return null;
1465 }
1466
1467 DBInfo info = coll_db.getInfo(srcFile);
1468 if (info == null)
1469 {
1470 _errorStatus = ERROR_DATA_NOT_FOUND_IN_DATABASE;
1471 coll_db.closeDatabase();
1472 return null;
1473 }
1474
1475 String oid = info.getInfo("oid");
1476
1477 coll_db.closeDatabase();
1478 return oid;
1479 }
1480
1481 /**
1482 * Checks to see if a document or section at a given OID exists.
1483 *
1484 * @param oid
1485 * is the identifier of the document/section to check.
1486 * @param collection
1487 * is the collection to search in.
1488 * @return true if the document/section exists, false otherwise.
1489 */
1490 public boolean archiveCheckDocumentOrSectionExists(String oid, String collection, String lang, String uid)
1491 {
1492 _errorStatus = NO_ERROR;
1493 SimpleCollectionDatabase coll_db = openDatabase(collection, ARCHIVEINFDOC, SimpleCollectionDatabase.READ, lang, uid);
1494 if (coll_db == null)
1495 {
1496 _errorStatus = ERROR_COULD_NOT_OPEN_DATABASE;
1497 return false;
1498 }
1499
1500 boolean section = false;
1501 if (oid.contains("."))
1502 {
1503 section = true;
1504 }
1505
1506 DBInfo info = null;
1507 if (section)
1508 {
1509 info = coll_db.getInfo(oid.substring(0, oid.indexOf(".")));
1510 }
1511 else
1512 {
1513 info = coll_db.getInfo(oid);
1514 }
1515 boolean exists = (info != null);
1516
1517 coll_db.closeDatabase();
1518 if (section && exists)
1519 {
1520 Document docXML = getDocXML(oid, collection, lang, uid);
1521 if (getSectionBySectionNumber(docXML, getSectionFromOID(oid)) == null)
1522 {
1523 return false;
1524 }
1525 return true;
1526 }
1527
1528 return exists;
1529 }
1530
1531 /**
1532 * Can be used to write a series of entries to the document database.
1533 *
1534 * @param oid
1535 * is the key that the entries will be written to.
1536 * @param collection
1537 * is the collection whose database will be written to.
1538 * @param infoList
1539 * is the list of entries to write.
1540 */
1541 public void archiveWriteEntryToDatabase(String oid, String collection, HashMap<String, ArrayList<String>> infoList, String lang, String uid)
1542 {
1543 _errorStatus = NO_ERROR;
1544 if (oid == null || oid.equals(""))
1545 {
1546 _errorStatus = ERROR_OID_NOT_SPECIFIED;
1547 return;
1548 }
1549 else if (collection == null || collection.equals(""))
1550 {
1551 _errorStatus = ERROR_COLLECTION_NOT_SPECIFIED;
1552 return;
1553 }
1554
1555 DBInfo info = new DBInfo();
1556
1557 for (String s : infoList.keySet())
1558 {
1559 for (String v : infoList.get(s))
1560 {
1561 info.addInfo(s, v);
1562 }
1563 }
1564
1565 SimpleCollectionDatabase coll_db = openDatabase(collection, ARCHIVEINFDOC, SimpleCollectionDatabase.WRITE, lang, uid);
1566 if (coll_db == null)
1567 {
1568 _errorStatus = ERROR_COULD_NOT_OPEN_DATABASE;
1569 return;
1570 }
1571 coll_db.setInfo(oid, info);
1572 coll_db.closeDatabase();
1573 }
1574
1575 /**
1576 * Can be used to remove an entry from the document database.
1577 *
1578 * @param oid
1579 * is the key of the entry to erase.
1580 * @param collection
1581 * is the collection whose database will have the entry removed.
1582 */
1583 public void archiveRemoveEntryFromDatabase(String oid, String collection, String lang, String uid)
1584 {
1585 _errorStatus = NO_ERROR;
1586 if (oid == null || oid.equals(""))
1587 {
1588 _errorStatus = ERROR_OID_NOT_SPECIFIED;
1589 return;
1590 }
1591 else if (collection == null || collection.equals(""))
1592 {
1593 _errorStatus = ERROR_COLLECTION_NOT_SPECIFIED;
1594 return;
1595 }
1596
1597 SimpleCollectionDatabase coll_db = openDatabase(collection, ARCHIVEINFDOC, SimpleCollectionDatabase.WRITE, lang, uid);
1598 if (coll_db == null)
1599 {
1600 _errorStatus = ERROR_COULD_NOT_OPEN_DATABASE;
1601 return;
1602 }
1603 coll_db.deleteKey(oid);
1604 coll_db.closeDatabase();
1605 }
1606
1607 /**
1608 * Gets the list of associated files for a given document.
1609 * @param oid is the identifier that will be used to search for associated documents.
1610 * @param collection is the collection whose database will be searched.
1611 * @return the list of associated files.
1612 */
1613 public ArrayList<String> archiveGetAssociatedImportFiles(String oid, String collection, String lang, String uid)
1614 {
1615 _errorStatus = NO_ERROR;
1616 if (oid == null || oid.equals(""))
1617 {
1618 _errorStatus = ERROR_OID_NOT_SPECIFIED;
1619 return null;
1620 }
1621 else if (collection == null || collection.equals(""))
1622 {
1623 _errorStatus = ERROR_COLLECTION_NOT_SPECIFIED;
1624 return null;
1625 }
1626
1627 SimpleCollectionDatabase coll_db = openDatabase(collection, ARCHIVEINFDOC, SimpleCollectionDatabase.READ, lang, uid);
1628 if (coll_db == null)
1629 {
1630 _errorStatus = ERROR_COULD_NOT_OPEN_DATABASE;
1631 return null;
1632 }
1633
1634 DBInfo info = coll_db.getInfo(oid);
1635 if (info == null)
1636 {
1637 _errorStatus = ERROR_DATA_NOT_FOUND_IN_DATABASE;
1638 coll_db.closeDatabase();
1639 return null;
1640 }
1641
1642 String srcFile = info.getInfo("src-file");
1643 Vector data = info.getMultiInfo("assoc-file");
1644
1645 ArrayList<String> assocFiles = new ArrayList<String>();
1646 assocFiles.add(srcFile);
1647 for (String d : (Vector<String>) data)
1648 {
1649 assocFiles.add(d);
1650 }
1651
1652 coll_db.closeDatabase();
1653 return assocFiles;
1654 }
1655
1656 /********************
1657 * Helper functions *
1658 *******************/
1659
1660 public boolean checkError(Element elem, String methodName)
1661 {
1662 if (_errorMessageMap.get(_errorStatus) != null)
1663 {
1664 GSXML.addError(elem.getOwnerDocument(), elem, methodName + ": " + _errorMessageMap.get(_errorStatus), GSXML.ERROR_TYPE_SYNTAX);
1665 return true;
1666 }
1667
1668 return false;
1669 }
1670
1671 public String getSectionFromOID(String oid)
1672 {
1673 if (!oid.contains("."))
1674 {
1675 return null;
1676 }
1677 return oid.substring(oid.indexOf(".") + 1);
1678 }
1679
1680 public Element createElementWithValue(Document doc, String nodeName, String name, String value)
1681 {
1682 Element metadataElem = doc.createElement(nodeName);
1683 metadataElem.setAttribute(GSXML.NAME_ATT, name);
1684 Node textNode = doc.createTextNode(value);
1685 metadataElem.appendChild(textNode);
1686 return metadataElem;
1687 }
1688
1689 public int getOperation(String to, String from)
1690 {
1691 int op;
1692 if (!to.contains(".") && !from.contains("."))
1693 {
1694 op = OPERATION_TYPE_DOC_TO_DOC;
1695 }
1696 else if (!to.contains(".") && from.contains("."))
1697 {
1698 op = OPERATION_TYPE_DOC_TO_SEC;
1699 }
1700 else if (to.contains(".") && !from.contains("."))
1701 {
1702 op = OPERATION_TYPE_SEC_TO_DOC;
1703 }
1704 else
1705 {
1706 op = OPERATION_TYPE_SEC_TO_SEC;
1707 }
1708 return op;
1709 }
1710
1711 public int[] oidToSectionNumberArray(String oid) throws Exception
1712 {
1713 String[] strLevels = oid.split("\\.");
1714 int[] intLevels = new int[strLevels.length - 1];
1715
1716 for (int i = 1; i < strLevels.length; i++) //Start at 1 to avoid the document identifier part of the OID
1717 {
1718 intLevels[i - 1] = Integer.parseInt(strLevels[i]);
1719 }
1720
1721 return intLevels;
1722 }
1723
1724 public String getDocFilePathFromDatabase(String oid, String collection, String lang, String uid)
1725 {
1726 SimpleCollectionDatabase coll_db = openDatabase(collection, ARCHIVEINFDOC, SimpleCollectionDatabase.WRITE, lang, uid);
1727 if (coll_db == null)
1728 {
1729 return null;
1730 }
1731 DBInfo info = coll_db.getInfo(oid);
1732 if (info == null)
1733 {
1734 return null;
1735 }
1736
1737 String docFile = info.getInfo("doc-file");
1738 coll_db.closeDatabase();
1739 return docFile;
1740 }
1741
1742 public boolean deleteDirectory(File current)
1743 {
1744 try
1745 {
1746 if (current == null || !current.exists())
1747 {
1748 return false;
1749 }
1750
1751 if (!current.isDirectory())
1752 {
1753 current.delete();
1754 return true;
1755 }
1756
1757 for (File f : current.listFiles())
1758 {
1759 if (f.isDirectory())
1760 {
1761 deleteDirectory(f);
1762 }
1763 else
1764 {
1765 f.delete();
1766 }
1767 }
1768 current.delete();
1769 }
1770 catch (Exception ex)
1771 {
1772 return false;
1773 }
1774
1775 return true;
1776 }
1777
1778 public int checkOIDandCollection(String oid, String collection, String lang, String uid)
1779 {
1780 if (oid == null || oid.equals(""))
1781 {
1782 return ERROR_OID_NOT_SPECIFIED;
1783 }
1784
1785 if (collection == null || collection.equals(""))
1786 {
1787 return ERROR_COLLECTION_NOT_SPECIFIED;
1788 }
1789
1790 if (!archiveCheckDocumentOrSectionExists(oid, collection, lang, uid))
1791 {
1792 return ERROR_SOURCE_DOCUMENT_OR_SECTION_DOES_NOT_EXIST;
1793 }
1794 return NO_ERROR;
1795 }
1796
1797 protected static String generateOID()
1798 {
1799 return "temp";
1800 }
1801
1802 public boolean copyDirectory(File src, File dest)
1803 {
1804 if (src.isDirectory())
1805 {
1806 //If the destination directory does not exist then create it
1807 if (!dest.exists())
1808 {
1809 dest.mkdir();
1810 }
1811
1812 //Get all the files in the directory
1813 String files[] = src.list();
1814 for (String file : files)
1815 {
1816 File srcFile = new File(src, file);
1817 File destFile = new File(dest, file);
1818
1819 if (!copyDirectory(srcFile, destFile))
1820 {
1821 return false;
1822 }
1823 }
1824 }
1825 else
1826 {
1827 try
1828 {
1829 FileChannel in = new FileInputStream(src).getChannel();
1830 FileChannel out = new FileOutputStream(dest).getChannel();
1831
1832 in.transferTo(0, in.size(), out);
1833
1834 in.close();
1835 out.close();
1836 }
1837 catch (Exception ex)
1838 {
1839 ex.printStackTrace();
1840 return false;
1841 }
1842 }
1843 return true;
1844 }
1845
1846 public Element getTopLevelSectionElement(Document docXML)
1847 {
1848 return (Element) GSXML.getChildByTagName(docXML.getDocumentElement(), GSXML.DOCXML_SECTION_ELEM);
1849 }
1850
1851 public boolean writeXMLFile(Document doc, String oid, String collection, String lang, String uid)
1852 {
1853 try
1854 {
1855 DOMSource source = new DOMSource(doc);
1856
1857 String test = archiveGetDocumentFilePath(oid, collection, lang, uid);
1858 File xmlFile = new File(test);
1859 Result result = new StreamResult(xmlFile);
1860
1861 Transformer transformer = TransformerFactory.newInstance().newTransformer();
1862 transformer.transform(source, result);
1863 }
1864 catch (Exception ex)
1865 {
1866 return false;
1867 }
1868 return true;
1869 }
1870
1871 public Document getDocXML(String oid, String collection, String lang, String uid)
1872 {
1873 if (oid.contains("."))
1874 {
1875 oid = oid.substring(0, oid.indexOf("."));
1876 }
1877
1878 Document docXML = null;
1879 if ((docXML = _docCache.get(oid + "__" + collection)) == null)
1880 {
1881 String filePath = archiveGetDocumentFilePath(oid, collection, lang, uid);
1882 File docFile = new File(filePath);
1883
1884 if (!docFile.exists())
1885 {
1886 return null;
1887 }
1888
1889 try
1890 {
1891 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
1892 DocumentBuilder db = dbf.newDocumentBuilder();
1893 docXML = db.parse(docFile);
1894
1895 _docCache.put(oid + "__" + collection, docXML);
1896 }
1897 catch (Exception ex)
1898 {
1899 return null;
1900 }
1901 }
1902 return docXML;
1903 }
1904
1905 public ArrayList<Element> getMetadataElementsFromSection(Document docXML, String oid, String metadataName)
1906 {
1907 if (oid.contains("."))
1908 {
1909 Element section = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
1910 return getMetadataElementsFromSection(section, metadataName);
1911 }
1912 else
1913 {
1914 return getMetadataElementsFromSection(getTopLevelSectionElement(docXML), metadataName);
1915 }
1916 }
1917
1918 public ArrayList<Element> getMetadataElementsFromSection(Element section, String metadataName)
1919 {
1920 Element description = (Element) GSXML.getChildByTagName(section, GSXML.DOCXML_DESCRIPTION_ELEM);
1921 if (description == null)
1922 {
1923 return null;
1924 }
1925
1926 ArrayList<Element> elemList = new ArrayList<Element>();
1927 NodeList metadataNodes = GSXML.getChildrenByTagName(description, GSXML.DOCXML_METADATA_ELEM);
1928 for (int j = 0; j < metadataNodes.getLength(); j++)
1929 {
1930 //If this is a metadata element with the requested name then we have found what we are looking for
1931 if (((Element) metadataNodes.item(j)).getAttribute(GSXML.NAME_ATT).equals(metadataName))
1932 {
1933 elemList.add((Element) metadataNodes.item(j));
1934 }
1935 }
1936
1937 return elemList;
1938 }
1939
1940 public Element getSectionBySectionNumber(Document docXML, String sectionNum)
1941 {
1942 return getSectionBySectionNumber(getTopLevelSectionElement(docXML), sectionNum);
1943 }
1944
1945 public Element getSectionBySectionNumber(Element current, String sectionNum)
1946 {
1947 if (sectionNum == null || sectionNum.equals(""))
1948 {
1949 return current;
1950 }
1951
1952 try
1953 {
1954 String[] levels = sectionNum.split("\\.");
1955 int currentSectionNum = Integer.parseInt(levels[0]);
1956
1957 NodeList sections = GSXML.getChildrenByTagName(current, GSXML.DOCXML_SECTION_ELEM);
1958
1959 if (levels.length > 1)
1960 {
1961 return getSectionBySectionNumber((Element) sections.item(currentSectionNum - 1), sectionNum.substring(sectionNum.indexOf(".") + 1));
1962 }
1963 else
1964 {
1965 return (Element) sections.item(currentSectionNum - 1);
1966 }
1967 }
1968 catch (Exception ex)
1969 {
1970 return null;
1971 }
1972 }
1973
1974 public String getDatabaseTypeFromCollection(String collection, String lang, String uid)
1975 {
1976 //Find out what kind of database we have
1977 Element dbTypeMessage = _mainDoc.createElement(GSXML.MESSAGE_ELEM);
1978 Element dbTypeRequest = GSXML.createBasicRequest(_mainDoc, GSXML.REQUEST_TYPE_DESCRIBE, collection, lang, uid);
1979 dbTypeMessage.appendChild(dbTypeRequest);
1980 Element dbTypeResponse = (Element) _router.process(dbTypeMessage);
1981
1982 String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.COLLECTION_ELEM);
1983 Element collectionElem = (Element) GSXML.getNodeByPath(dbTypeResponse, path);
1984
1985 if (collectionElem != null)
1986 {
1987 return collectionElem.getAttribute(GSXML.DB_TYPE_ATT);
1988 }
1989 return "gdbm"; //The default collection database type
1990 }
1991
1992 public SimpleCollectionDatabase openDatabase(String collection, String dbName, int readWrite, String lang, String uid)
1993 {
1994 //Find out what kind of database we have
1995 String databaseType = getDatabaseTypeFromCollection(collection, lang, uid);
1996 String dbExt = DBHelper.getDBExtFromDBType(databaseType);
1997
1998 SimpleCollectionDatabase coll_db = new SimpleCollectionDatabase(databaseType);
1999 if (!coll_db.databaseOK())
2000 {
2001 System.err.println("Couldn't create the collection database of type " + databaseType);
2002 return null;
2003 }
2004
2005 coll_db.openDatabase(_siteHome + File.separatorChar + "collect" + File.separatorChar + collection + File.separatorChar + "archives" + File.separatorChar + dbName + dbExt, readWrite);
2006
2007 return coll_db;
2008 }
2009}
Note: See TracBrowser for help on using the repository browser.