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

Last change on this file since 37177 was 37177, checked in by davidb, 15 months ago

Introduction of new optional parameter docVersion. If null (or equal to the empty string), then code works as before. Designed to work with the file-level document-version history mechanism, if non-empty, then this value is used to change where doc.xml on the file system is read from

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