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

Last change on this file since 29224 was 29224, checked in by kjdon, 10 years ago

commenting out the doc xml cache. When doing doc editing through a collection, metadata changes are currently handled by metadata-server.pl. This edits files directly, not through DocumentMaker using this class. Therefore the doc xml cache gets out of date, and you lose metadata changes if you then edit the text

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