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

Last change on this file was 37596, checked in by kjdon, 13 months ago

we need to ignore the dtd when reading in the doc.xml. old collections mayuse http://, which they can't access properly.

  • Property svn:executable set to *
File size: 67.8 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 // ignore the dtd
2051 dbf.setFeature("http://xml.org/sax/features/validation", false);
2052 dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
2053 DocumentBuilder db = dbf.newDocumentBuilder();
2054 docXML = db.parse(docFile);
2055
2056 //_docCache.put(oid + "__" + collection, docXML);
2057 }
2058 catch (Exception ex)
2059 {
2060 return null;
2061 }
2062 // }
2063 return docXML;
2064 }
2065
2066 public ArrayList<Element> getMetadataElementsFromSection(Document docXML, String oid, String metadataName)
2067 {
2068 if (oid.contains("."))
2069 {
2070 Element section = getSectionBySectionNumber(docXML, getSectionFromOID(oid));
2071 return getMetadataElementsFromSection(section, metadataName);
2072 }
2073 else
2074 {
2075 return getMetadataElementsFromSection(getTopLevelSectionElement(docXML), metadataName);
2076 }
2077 }
2078
2079 public ArrayList<Element> getMetadataElementsFromSection(Element section, String metadataName)
2080 {
2081 Element description = (Element) GSXML.getChildByTagName(section, GSXML.DOCXML_DESCRIPTION_ELEM);
2082 if (description == null)
2083 {
2084 return null;
2085 }
2086
2087 ArrayList<Element> elemList = new ArrayList<Element>();
2088 NodeList metadataNodes = GSXML.getChildrenByTagName(description, GSXML.DOCXML_METADATA_ELEM);
2089 for (int j = 0; j < metadataNodes.getLength(); j++)
2090 {
2091 //If this is a metadata element with the requested name then we have found what we are looking for
2092 if (((Element) metadataNodes.item(j)).getAttribute(GSXML.NAME_ATT).equals(metadataName))
2093 {
2094 elemList.add((Element) metadataNodes.item(j));
2095 }
2096 }
2097
2098 return elemList;
2099 }
2100
2101 public Element getSectionBySectionNumber(Document docXML, String sectionNum)
2102 {
2103 return getSectionBySectionNumber(getTopLevelSectionElement(docXML), sectionNum);
2104 }
2105
2106 public Element getSectionBySectionNumber(Element current, String sectionNum)
2107 {
2108 if (sectionNum == null || sectionNum.equals(""))
2109 {
2110 return current;
2111 }
2112
2113 try
2114 {
2115 String[] levels = sectionNum.split("\\.");
2116 int currentSectionNum = Integer.parseInt(levels[0]);
2117
2118 NodeList sections = GSXML.getChildrenByTagName(current, GSXML.DOCXML_SECTION_ELEM);
2119 if (levels.length > 1)
2120 {
2121 return getSectionBySectionNumber((Element) sections.item(currentSectionNum - 1), sectionNum.substring(sectionNum.indexOf(".") + 1));
2122 }
2123 else
2124 {
2125 return (Element) sections.item(currentSectionNum - 1);
2126 }
2127 }
2128 catch (Exception ex)
2129 {
2130 return null;
2131 }
2132 }
2133
2134 public String getDatabaseTypeFromCollection(String collection, UserContext userContext)
2135 {
2136 //Find out what kind of database we have
2137 Document doc = XMLConverter.newDOM();
2138 Element dbTypeMessage = doc.createElement(GSXML.MESSAGE_ELEM);
2139 Element dbTypeRequest = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, collection, userContext);
2140 dbTypeMessage.appendChild(dbTypeRequest);
2141 Element dbTypeResponse = (Element) _router.process(dbTypeMessage);
2142
2143 String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.COLLECTION_ELEM);
2144 Element collectionElem = (Element) GSXML.getNodeByPath(dbTypeResponse, path);
2145
2146 if (collectionElem != null)
2147 {
2148 return collectionElem.getAttribute(GSXML.DB_TYPE_ATT);
2149 }
2150 return "gdbm"; //The default collection database type
2151 }
2152
2153 public SimpleCollectionDatabase openDatabase(String collection, String dbName, int readWrite, UserContext userContext)
2154 {
2155 //Find out what kind of database we have
2156 String databaseType = getDatabaseTypeFromCollection(collection, userContext);
2157 String dbExt = DBHelper.getDBExtFromDBType(databaseType);
2158
2159 SimpleCollectionDatabase coll_db = new SimpleCollectionDatabase(databaseType);
2160 if (!coll_db.databaseOK())
2161 {
2162 System.err.println("Couldn't create the collection database of type " + databaseType);
2163 return null;
2164 }
2165
2166 coll_db.openDatabase(GSFile.collectionArchiveDir(_siteHome, collection) + File.separatorChar + dbName + dbExt, readWrite);
2167
2168 return coll_db;
2169 }
2170
2171 public int operationStringToInt(String operation)
2172 {
2173 if (operation.equals("insertBefore"))
2174 {
2175 return OPERATION_INSERT_BEFORE;
2176 }
2177 else if (operation.equals("insertAfter"))
2178 {
2179 return OPERATION_INSERT_AFTER;
2180 }
2181 else if (operation.equals("append"))
2182 {
2183 return OPERATION_APPEND;
2184 }
2185 else
2186 {
2187 return OPERATION_REPLACE;
2188 }
2189 }
2190
2191 public int getErrorStatus()
2192 {
2193 return _errorStatus;
2194 }
2195}
Note: See TracBrowser for help on using the repository browser.