source: other-projects/trunk/gs3-webservices-democlient/src/GS3DemoClient/org/greenstone/gs3client/data/DocumentNodeData.java@ 15222

Last change on this file since 15222 was 15222, checked in by ak19, 16 years ago

Greenstone3 web services demo-clientadded to GS3's other-projects

File size: 24.1 KB
Line 
1/**
2 *#########################################################################
3 * DocumentNodeData.java - part of the demo-client for Greenstone 3, of the
4 * Greenstone digital library suite from the New Zealand Digital Library
5 * Project at the * University of Waikato, New Zealand.
6 * <BR><BR>
7 * Copyright (C) 2008 New Zealand Digital Library Project
8 * <BR><BR>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 * <BR><BR>
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *########################################################################
19 */
20
21package org.greenstone.gs3client.data;
22
23import java.util.Iterator;
24import java.util.Vector;
25import java.util.Map;
26import java.util.HashMap;
27import java.util.Map.Entry;
28
29import org.w3c.dom.Element;
30import org.w3c.dom.Node;
31import org.w3c.dom.NodeList;
32import org.greenstone.gsdl3.util.GSXML;
33
34
35/**
36 * Represents the data stored in the &lt;documentNode&gt; Elements
37 * of Greenstone 3's XML response messages. A DocumentNodeData may
38 * have descendants of type DocumentNodeData. Some DocumentNodeData
39 * objects are the root of a structure, others are internal nodes or
40 * leaves.
41 * See p.47 to p.49 in the manual.
42 * @author ak19
43 */
44public class DocumentNodeData extends NodeData {
45 /** NodeType of this DocumentNodeData: root, internal or leaf */
46 public final String nodeType;
47 /** DocType can be Hierarchical for instance */
48 public final String docType;
49 /** Rank of this DocumentNodeData if the &lt;documentNode&gt;
50 * Element was returned in a search result */
51 public final double rank;
52
53 // not set initially, only set after calling
54 // setDescendentsOfRootNode(<nodeStructure>)
55 /** Reference to this doc's root */
56 protected DocumentNodeData rootDoc = null;
57 /** children of this node: part of &lt;nodeStructure&gt; Element */
58 protected DocumentNodeData[] childnodes = null;
59
60 /** A Hashmap to store &lt;nodeStructureInfo&gt; of a DocumentNodeData
61 * (if it has any) */
62 protected HashMap nodeStructureInfo_map = null;
63
64 /** The text content of the document */
65 protected String nodeContent = null;
66
67 /** Given tags of the form
68 * &lt;documentNode nodeID="HASHac0a04dd14571c60d7fbfd.4.2"
69 * nodeType="x" docType="y"&gt;
70 * &lt;nodeContent>Text&lt;/nodeContent&gt;
71 * &lt;nodeStructureInfo>&lt;info name="i" value="1" /&gt;
72 * &lt;info name = "ii" value = "2" /&gt;&lt;/nodeStructureInfo&gt;
73 * &lt;metadataList&gt;&lt;metadata name="a"&gt;Value
74 * &lt;/metadata&gt;&lt;/metadataList&gt;
75 * &lt;nodeStructure&gt;
76 * &lt;documentNode ....>&lt;/documentNode&gt;
77 * &lt;documentNode ....>&lt;/documentNode&gt;
78 * &lt;/nodeStructure&gt;
79 * &lt;/documentNode&gt;
80 * this constructor extracts the nodeId out of it and any other fields
81 * that might be set in the docNodeTag &lt;documentNode&gt; element.
82 * @param docNodeTag is an &lt;documentNode&gt; XML element to construct
83 * this DocumentNodeData object from
84 */
85 public DocumentNodeData(Element docNodeTag){
86 // We'd definitely have the nodeID attribute, but to be on the safe
87 // side:
88 super(docNodeTag);
89
90 // this.nodeType and this.docType will be set: these attributes are
91 // there in the <documentNode> elements of all Query Responses as
92 // well as in <documentNode>s of documentStructureRetrieve responses.
93 this.nodeType = docNodeTag.hasAttribute(GSXML.NODE_TYPE_ATT) ?
94 docNodeTag.getAttribute(GSXML.NODE_TYPE_ATT)
95 : GSXML.NODE_TYPE_ROOT; //DEFAULTING TO ROOT IF NONE SPECIFIED!
96
97 this.docType = docNodeTag.hasAttribute(GSXML.DOC_TYPE_ATT) ?
98 docNodeTag.getAttribute(GSXML.DOC_TYPE_ATT) : "";
99 // OR default to GSXML.DOC_TYPE_SIMPLE????
100
101 String rankVal = docNodeTag.hasAttribute(GSXML.NODE_RANK_ATT) ?
102 docNodeTag.getAttribute(GSXML.NODE_RANK_ATT) : "0";
103 this.rank = Double.parseDouble(rankVal);
104
105 // If <documentNode> has no <metadataList> child, then member variable
106 // metadataList remains null and can be set later if and as required.
107 setMetadataList(docNodeTag);
108
109 // structureInfo either initialised if there <documentNode> has a child
110 // element called <nodeStructureInfo>, else it remains null.
111 setNodeStructInfo(docNodeTag);
112
113 // Sets member nodeContent (the text content of the document) to the
114 // document's text if this <documentNode> has a child <nodeContent>.
115 // If there is no such child, nodeContent will be set to empty string.
116 setNodeContent(docNodeTag);
117 }
118
119 /** Given a &lt;nodeStructure&gt;&lt;/nodeStructure&gt; element returned
120 * from a request for the *ENTIRE* nodeStructure, this method will find the
121 * &lt;documentNode&gt; that is the Root (nodeType=ROOT) and from there
122 * on proceed to set all descendent &lt;documentNode&gt;s.
123 * If either the root or any descendent &lt;documentNode&gt;s have already
124 * been instantiated at any point during program execution, it will
125 * be reused, else a new object representing that descendent/root
126 * &lt;documentNode&gt; will be created.
127 * The nodeIDsToDocNodes_map is a mapping of nodeIDs to existing
128 * documentNodeData objects, so that the DocumentNodeData objects with
129 * the same ID need not be instantiated where they already exist.
130 * This method returns the rootNode if it completes successfully,
131 * otherwise it returns null.
132 * @param nodeStructure is the &lt;nodeStructure&gt;&lt;/nodeStructure&gt;
133 * element returned from a request for the *ENTIRE* nodeStructure
134 * @param nodeIDsToDocNodes_map is the Map of node IDs to DocumentNodeData
135 * objects being maintained
136 * @return the root DocumentNodeData object of the &lt;documentNode&gt;s
137 * in the &lt;nodeStructure&gt;
138 */
139 public DocumentNodeData setDescendentsOfRootNode(Element nodeStructure,
140 Map nodeIDsToDocNodes_map)
141 {
142 // First find <documentNode> inside <nodeStructure> where
143 // nodeType==ROOT. This always happens to be the first
144 // <documentNode> child of <nodeStructure>
145 // Use this root <docNode> to set its children and all descendents
146 // If there is no <docNode nodetype==ROOT>, return false.
147 Element rootDocNodeTag = ParseUtil.getFirstChildElementCalled(
148 nodeStructure, GSXML.DOC_NODE_ELEM);
149
150 // These cases shouldn't occur, but to be on the safe side -
151 // Actually, this happens with project gutenberg searches: where
152 // docType and nodeType are not set and the <nodeStructure>
153 // contains no child <documentNode>. In such cases, make this
154 // documentNodeData the root.
155 if(rootDocNodeTag == null) {
156 rootDoc = this;
157 return rootDoc;
158 }
159 String type = rootDocNodeTag.getAttribute(GSXML.NODE_TYPE_ATT);
160 if(!type.equals(GSXML.NODE_TYPE_ROOT)) {
161 rootDoc = this; // Case of first <docNode> of <nodeStructure>
162 return rootDoc; // nodetype != root -> this shouldn't happen
163 // but if there's only 1 node and it's a leaf, make it
164 // the root. This actually happens in simple image collections
165 // which have no substructures containing further images
166 //return null;
167 }
168 // We found the root node Element we want, get its NodeID,
169 // and then start processing the root node for descendents
170 String ID = rootDocNodeTag.hasAttribute(GSXML.NODE_ID_ATT) ?
171 rootDocNodeTag.getAttribute(GSXML.NODE_ID_ATT) : "";
172
173 // try to find this ID in HashMap of already instantiated
174 // documentNodeData objects - if it exists, set children
175 // on that. If it doesn't, then create new object and set
176 // the children+descendents on that. (Creating new object
177 // will automatically add it to the hashMap
178 DocumentNodeData root = null;
179 if(nodeIDsToDocNodes_map.containsKey(ID))
180 root = (DocumentNodeData)nodeIDsToDocNodes_map.get(ID);
181 else {
182 // not in HashMap, so create a new docNode (this will set
183 // nodeType and docType) and add it to the map
184 root = new DocumentNodeData(rootDocNodeTag);
185 nodeIDsToDocNodes_map.put(root.nodeID, root);
186 }
187
188 this.rootDoc = root;
189
190 // either way, we have a root node now, so set its children
191 root.setDescendents(root, rootDocNodeTag, nodeIDsToDocNodes_map);
192 // docNodeTag of root
193
194 return root;
195 }
196
197
198 /**
199 * Recursive method.
200 * Called by setDescendentsOfRootNode(). Given a docNodeTag (of the Root)
201 * which was nested within a &lt;nodeStructure&gt; element, this method sets
202 * all the descendents of that root. This means that each documentNodeData
203 * object in the hierarchy of the root will have its childnodes[] variable
204 * set, iff that object is not a nodeType==LEAF. With leaves, the
205 * childnodes array will remain null.
206 * The nodeIDsToDocNodes_map is a mapping of nodeIDs to existing
207 * documentNodeData objects, so that the DocumentNodeData objects with the
208 * same ID need not be instantiated where they already exist.
209 * @param root - the root element of this documentNodeData
210 * @param docNodeTag - the &lt;documentNode&gt; XML Element of the Root
211 * nested within a &lt;nodeStructure&gt; element
212 * @param nodeIDsToDocNodes_map is the Map of node IDs to DocumentNodeData
213 * objects being maintained
214 */
215 protected void setDescendents(DocumentNodeData root, Element docNodeTag,
216 Map nodeIDsToDocNodes_map)
217 {
218 if(this.nodeType.equals(GSXML.NODE_TYPE_LEAF))
219 return; // no children
220
221 Vector children = ParseUtil.getAllChildElementsCalled(
222 docNodeTag, GSXML.DOC_NODE_ELEM);
223 if(children == null) // shouldn't have to check this, as the check
224 // on nodeType==LEAF above would have been enough
225 return; // no children, hence no descendents
226
227 // else, obtain and instantiate DocumentNodeData objects
228 // on each of the children
229 this.childnodes = new DocumentNodeData[children.size()];
230 for(int i = 0; i < childnodes.length; i++) {
231 Element childDocNodeTag = (Element)children.get(i);
232 String ID = childDocNodeTag.hasAttribute(GSXML.NODE_ID_ATT) ?
233 childDocNodeTag.getAttribute(GSXML.NODE_ID_ATT) : "";
234
235 if(nodeIDsToDocNodes_map.containsKey(ID))
236 childnodes[i]
237 = (DocumentNodeData)nodeIDsToDocNodes_map.get(ID);
238 else { //not yet in the map of documentNodeData objects, so
239 // create a new DocumentNodeData and add it to the map
240 childnodes[i] = new DocumentNodeData(childDocNodeTag);
241 nodeIDsToDocNodes_map.put(childnodes[i].nodeID, childnodes[i]);
242 }
243 // set the root for the descendent:
244 childnodes[i].rootDoc = root;
245 // Now set its children and so on until all descendents indicated
246 // in the <nodestructure><documentNode /></nodestructure> have
247 // been set.
248 childnodes[i].setDescendents(
249 root, childDocNodeTag, nodeIDsToDocNodes_map);
250 }
251 }
252
253 /* Can call these methods later as well (after constructor). If the
254 * docNodeTag passed to the constructor did not have these attributes,
255 * can set them later with a docNodeTag of the same nodeID that does
256 * have these attributes set. */
257
258 /** Sets structureInfo member variable &lt;nodeStructureInfo&gt; element is
259 * present as child of &lt;documentNode&gt;, else value of structureInfo
260 * remains unchanged. A &lt;docNode&gt; has no more than one child
261 * &lt;nodeStructureInfo&gt; in a response to a DocumentStructureRetrieve.
262 * However, the response can contain many such &lt;docNodes&gt;.
263 * See manual p.49.
264 * @param docNodeTag is the &lt;documentNode&gt; XML element containing
265 * the &lt;nodeStructureInfo&gt; Element that is to be processed */
266 public void setNodeStructInfo(Element docNodeTag) {
267 NodeList nl = docNodeTag.getElementsByTagName(
268 GSXML.NODE_STRUCTURE_ELEM+GSXML.INFO_ATT);
269 if(nl.getLength() > 0) {
270 // get the first <nodeStructureInfo> (which will be the only
271 // <nodeStructureInfo> for this <docNode>
272 Element nodeStructInfoTag = (Element)nl.item(0);
273 nl = null;
274 // Get any children <info> tags and extract data-values from them
275 nl = nodeStructInfoTag.getElementsByTagName("info");
276 int size = nl.getLength();
277 if(size > 0) {
278 nodeStructureInfo_map = new HashMap(size);
279 for(int i = 0; i < size; i++) {
280 Element infoTag = (Element)nl.item(i);
281 String name = infoTag.hasAttribute(GSXML.NAME_ATT) ?
282 infoTag.getAttribute(GSXML.NAME_ATT) : "";
283 String value = infoTag.hasAttribute(GSXML.VALUE_ATT) ?
284 infoTag.getAttribute(GSXML.VALUE_ATT) : "";
285 nodeStructureInfo_map.put(name, value);
286 }
287 }
288 }
289 // in all other cases, nodeStructureInfo_map remains null
290 }
291
292 /** Sets member variable nodeContent with the text (if any) inside any
293 * &lt;nodeContent&gt;&lt;/nodeContent&gt; child element of
294 * &lt;documentNode&gt;, else the value of nodeContent is set to empty
295 * string (""). The empty string will prevent it from being retrieved again
296 * and again (which would happen if nodeContent remained at null) if it had
297 * already been retrieved once.
298 * However, if the docNodeTag parameter is not the response from
299 * a documentContentRetrieve (if it doesn't have the proper XML
300 * structure for that), nodeContent remains null and can be set
301 * in future when given an appropriate docNodeTag.
302 * @param docNodeTag is the &lt;documentNode&gt; XML element containing
303 * the content information for this DocumentNodeData object */
304 public void setNodeContent(Element docNodeTag) {
305 Element nodeContentTag = ParseUtil.getFirstChildElementCalled(
306 docNodeTag, GSXML.NODE_CONTENT_ELEM);
307 if(nodeContentTag != null) { //such a child tag exists
308 //obtain its child textNode and the value thereof
309 Node content = nodeContentTag.getFirstChild();
310 // content will be null if <nodeContent /> instead of
311 // <nodeContent></nodeContent>
312 this.nodeContent
313 = (content == null) ? "" : content.getNodeValue();
314
315 // Now to fix the html if it's not already proper:
316 if(nodeContent.startsWith("<Sec>")) { // remove starting <Sec>
317 // it's not a recognised tag in html
318 nodeContent = nodeContent.substring(5);
319 nodeContent = nodeContent.trim();
320 if(nodeContent.startsWith("</")) {
321 // first closing bracket
322 int index = nodeContent.indexOf(">");
323 // remove any starting </B> or </I>
324 nodeContent = nodeContent.substring(index+1);
325 nodeContent = nodeContent.trim();
326 }
327 }
328 // Finally, make sure it has the proper starting (and ending tags)
329 if((!nodeContent.startsWith("<html>"))
330 || (!nodeContent.startsWith("<HTML>"))) {
331 nodeContent = "<html><head></head><body>"
332 + nodeContent + "</body></html>";
333 }
334 }
335 // else leave nodeContent as null, docNodeTag was not returned
336 // as the result of a docContentRetrieve response
337 }
338
339
340 /** @return the data stored in this DocumentNodeData object, all except
341 * the document content which can be accessed by calling toString().
342 * This method is useful for debugging purposes: to view what each
343 * field's values are. */
344 public String show() {
345 StringBuffer buf = new StringBuffer("nodeID: " + this.nodeID);
346 buf.append(" nodeType: " + this.nodeType);
347 buf.append(" docType: " + this.docType);
348
349 if(nodeStructureInfo_map != null) {
350 buf.append("NodeStructureInfo:");
351 Iterator i = nodeStructureInfo_map.entrySet().iterator();
352 while(i.hasNext()) {
353 Entry e = (Entry)i.next();
354 buf.append("\nname: " + (String)e.getKey());
355 buf.append(" value: " + (String)e.getValue());
356 }
357 }
358 buf.append("\n");
359 buf.append(showMeta());
360 return buf.toString();
361 }
362
363 /** @return true if the (nodeType of) this DocumentNodeData is a leaf */
364 public boolean isLeaf() { return nodeType.equals(GSXML.NODE_TYPE_LEAF); }
365
366 /* Accessor methods */
367 /** @return the nodeType of this DocumentNodeData */
368 public String getNodeType() { return nodeType; }
369 /** @return the docType of this DocumentNodeData */
370 public String getDocType() { return docType; }
371
372 /** @return the root of the structure of which this documentNodeData
373 * is part (this docNodeData is either the root itself or its child
374 * or descenedent). A null is returned if the Root docNode and its
375 * descendents have not been set yet. */
376 public DocumentNodeData getRoot() { return this.rootDoc; }
377
378 /** @return this document's text content (which may be empty string
379 * if there was none). It will return null if the nodeContent has
380 * not been set yet. */
381 public String getContent() { return nodeContent; }
382
383 /** @return an array of all this DocNode's children. Each childnode
384 * in turn, can further contain children, etc. Null is returned if
385 * there are no childnodes or if setDescendentsOfRootNode() has not
386 * been called (that is, if the root has not yet been set). */
387 public DocumentNodeData[] getDescendents() { return childnodes; }
388
389 /** @return gets the children (NodeData) of this DocumentNodeData
390 * but does not guarantee that their children are set. That is,
391 * it's possible that this DocumentNodeData's children may have
392 * children of their own but that these may not be set yet (and
393 * are temporarily still null). */
394 public NodeData[] getChildren() { return childnodes; }
395
396 /** When called on a rootNode, returns an array of all the descendents'
397 * nodeIDs. If this object is not a rootNode, it returns null.
398 * Parameter onlyTheUntitled, if true, makes this method return only the
399 * nodeIDs of those documentNodeData descendents for whom the title has
400 * not yet been set.
401 * If false, the nodeIDs of all dDcumentNodeData descendents will be
402 * returned, regardless of whether their titles are already set.
403 * @param onlyTheUntitled - if true this method is only to return those
404 * descendants' IDs whose titles have not yet been set. If false,
405 * all descendants' nodeIDs are returned.
406 * @return an array of all the descendant DocumentNodeData's NodeIDs */
407 public String[] getDescNodeIDsAsList(boolean onlyTheUntitled) {
408 String[] nodeIDs = null;
409 if(this.nodeType.equals(GSXML.NODE_TYPE_ROOT)) {
410 Vector v = new Vector();
411 if(!onlyTheUntitled || this.getTitle() == null)
412 v.add(this.nodeID); // add root only if its title not yet set
413 descNodeIDsAsList(v, this, onlyTheUntitled);
414 if(v.size() > 0) {
415 nodeIDs = new String[v.size()];
416 v.toArray(nodeIDs);
417 } // else if v.size() == 0, this method will return null
418 }
419 return nodeIDs;
420 }
421
422 /** Recursive method that adds all the nodeIDs of the descendents
423 * of DocumentNodeData parent into the Vector v.
424 * If parameter onlyTheUntitled=true, then only the nodeIDs of the
425 * untitled DocumentNodeData descendents are added in. Otherwise,
426 * all descendents' nodeIDs are.
427 * @param v is the Vector being populated with descendant documentNodeData's
428 * IDs.
429 * @param parent is the parent DocumentNodeData node currently being
430 * considered in this recursion step.
431 * @param onlyTheUntitled should be true if only those descendant
432 * DocumentNodeData objects that don't yet have a title need to be returned.
433 * If false, it returns all descendants' nodeIDs in the Vector v. */
434 protected static void descNodeIDsAsList(Vector v,
435 DocumentNodeData parent, boolean onlyTheUntitled)
436 {
437 // Recursion
438 // Base case:
439 if(parent.childnodes == null)
440 return;
441 for(int i = 0; i < parent.childnodes.length; i++) {
442 // Now comes step that does actual processing:
443
444 // if only asking for NodeIDs of descendents whose titles
445 // aren't set yet, then:
446 if(!onlyTheUntitled || parent.childnodes[i].getTitle() == null)
447 v.add(parent.childnodes[i].nodeID);
448 // above if-stmt should add the desc nodeID for either
449 // - all descendents (if onlyTheUntitled=true); or
450 // - otherwise, only for those whose title is not set yet
451
452 // Recursion step:
453 DocumentNodeData.descNodeIDsAsList(
454 v, parent.childnodes[i], onlyTheUntitled);
455 }
456 }
457
458 /** @return true if this documentNode's root is associated with the
459 * ImagePlug or PagedImgPlug.
460 * @see <a href="http://wiki.greenstone.org/wiki/gsdoc/tutorial/en/scanned_image_collection.htm">The scanned image collection, for names of Plugin metadata values PagedImgPlug and ImagePlug</a> */
461 public boolean canBeImage() {
462 if(this.rootDoc == null) {
463 return false;
464 }
465 // else
466 if(!this.rootDoc.nodeMetadata.containsKey("Plugin")) {
467 return false; // this shouldn't happen:
468 // I think every root has Plugin meta
469 }
470 // else
471 Vector values = (Vector)this.rootDoc.nodeMetadata.get("Plugin");
472 String plugin = (String)values.get(0);
473
474 final String imagePlug = "PagedImgPlug";
475 final String pagedImgPlug = "ImagePlug";
476 if(plugin.equals(pagedImgPlug) || plugin.equals(imagePlug))
477 return true;
478 else
479 return false;
480 }
481
482 /** @return value of "notext" metadata field, if any. If true, this
483 * indicates that the document is purely an image. Otherwise it indicates
484 * that there is both a text view and an image view associated with this
485 * document. */
486 public boolean hasNoText() {
487 if(this.nodeMetadata == null)
488 return false; // deal with any odd cases
489
490 if(!this.nodeMetadata.containsKey("NoText"))
491 return false; // no NoText metadata, so it probably has text
492 Vector values = (Vector)this.nodeMetadata.get("NoText");
493 String noText = (String)values.get(0);
494 int val = Integer.parseInt(noText);
495 return (val == 1); // 0 if it has text, 1 if indeed it has no text
496 }
497
498 /** @return the image url stored in the "srcicon" metadata field, if any. */
499 public String getImgURL() {
500 if(this.nodeMetadata == null)
501 return ""; // deal with any odd cases
502
503 if(!this.nodeMetadata.containsKey("srclink"))
504 return "";
505 Vector values = (Vector)this.nodeMetadata.get("srclink");
506 String imgTag = (String)values.get(0);
507 // now we got <a href="somelink">; extract just the "somelink" portion
508 int startindex = imgTag.indexOf('\"');
509 int endindex = imgTag.lastIndexOf('\"');
510 imgTag = imgTag.substring(startindex, endindex+1);
511
512 // remove the macro - if present - and replace it with the
513 // assocFilePath mentioned in the document's root's metadata
514 startindex = imgTag.indexOf('[');
515 if(startindex != -1 && imgTag.contains("assocfilepath")) {
516 if(this.rootDoc == null) // need root doc to get assocfilepath
517 return "";
518 // else
519 endindex = imgTag.indexOf(']');
520 imgTag = imgTag.substring(0, startindex)
521 + getAssocFilePath()
522 + imgTag.substring(endindex+1, imgTag.length());
523 }
524 return imgTag;
525 }
526
527 /** @return the Source metadata value which represents the image file
528 * name. Returns "" if this DocumentNodeData is not a root or does not
529 * have Source meta. */
530 public String getImgName() {
531 if(this.rootDoc == null)
532 return "";
533 // else
534 if(!this.nodeMetadata.containsKey("Source"))
535 return "";
536 // else
537 Vector values = (Vector)this.nodeMetadata.get("Source");
538 return (String)values.get(0);
539 }
540
541 /** @return the vector of values for metadata name "gsdlassocfile": a vector
542 * of MetaPairs(filename, mimetype).
543 * An empty vector is returned for all docNodes other than the root. And the
544 * root too need not always have associated files listed in its metadata. */
545 public Vector getAssociatedFileNames() {
546 Vector v = new Vector();
547 final char COLON = ':';
548 if(this.nodeMetadata.containsKey("gsdlassocfile")) {
549 Vector assocFileNames = (Vector)nodeMetadata.get("gsdlassocfile");
550 for(int i = 0; i < assocFileNames.size(); i++) {
551 // assocFileNames are stored in format "cover.jpg:image/jpeg:"
552 // need to split these to separate the name from the mimetype
553 String filename = (String)assocFileNames.get(i);
554 int firstColon = filename.indexOf(COLON);
555 String mimetype = filename.substring(
556 firstColon+1, filename.lastIndexOf(COLON));
557 filename = filename.substring(0, firstColon);
558 Pair p = new Pair(filename, mimetype);
559 // (we're not going to be sorting these pairs, so we make
560 // no use of each Pair's Comparable nature)
561 v.add(p);
562 }
563 }
564 return v; // returns empty vector if no gsdlassocfile metadata
565 }
566
567 /** @return the root document's assocfilepath metadata field, if any.
568 * This will indicate the directory path where the associated images
569 * and other files are stored. */
570 public String getAssocFilePath() {
571 if(this.rootDoc == null)
572 return "";
573 // else, check for rootDoc having "assocfilepath" metadata:
574 if(!rootDoc.nodeMetadata.containsKey("assocfilepath"))
575 return "";
576 Vector values = (Vector)rootDoc.nodeMetadata.get("assocfilepath");
577 return (String)values.get(0);
578 }
579}
Note: See TracBrowser for help on using the repository browser.