source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/AbstractBrowse.java@ 31592

Last change on this file since 31592 was 30634, checked in by kjdon, 8 years ago

modifying the way levels, indexes, classifier buttons are displayed. displayItem with specific lang takes priority, then displayItem with a key for dictionary lookup, then if no displayItems lookup the level/index name in hte dictionary

  • Property svn:keywords set to Author Date Id Revision
File size: 27.3 KB
Line 
1/*
2 * AbstractBrowse.java
3 * Copyright (C) 2005 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19package org.greenstone.gsdl3.service;
20
21// Greenstone classes
22import java.util.ArrayList;
23
24import org.apache.log4j.Logger;
25import org.greenstone.gsdl3.util.AbstractBasicDocument;
26import org.greenstone.gsdl3.util.BasicDocument;
27import org.greenstone.gsdl3.util.GSPath;
28import org.greenstone.gsdl3.util.GSXML;
29import org.greenstone.gsdl3.util.MacroResolver;
30import org.greenstone.gsdl3.util.OID;
31import org.greenstone.gsdl3.util.XMLConverter;
32
33import org.w3c.dom.Document;
34import org.w3c.dom.Element;
35import org.w3c.dom.Node;
36import org.w3c.dom.NodeList;
37
38/**
39 * Partially implements a generic classifier service
40 *
41 */
42public abstract class AbstractBrowse extends ServiceRack
43{
44
45 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.AbstractBrowse.class.getName());
46
47 // the browsing services
48 private static final String CLASSIFIER_SERVICE = "ClassifierBrowse";
49 private static final String CLASSIFIER_METADATA_SERVICE = "ClassifierBrowseMetadataRetrieve";
50
51 // do we want to keep info request?
52
53 protected static final String STRUCT_PARAM = "structure";
54 protected static final String INFO_PARAM = "info";
55
56 protected static final String STRUCT_ANCESTORS = "ancestors";
57 protected static final String STRUCT_PARENT = "parent";
58 protected static final String STRUCT_SIBS = "siblings";
59 protected static final String STRUCT_CHILDREN = "children";
60 protected static final String STRUCT_DESCENDS = "descendants";
61 protected static final String STRUCT_ENTIRE = "entire";
62
63 protected static final String INFO_NUM_SIBS = "numSiblings";
64 protected static final String INFO_NUM_CHILDREN = "numChildren";
65 protected static final String INFO_SIB_POS = "siblingPosition";
66
67 protected AbstractBasicDocument gs_doc = null;
68
69 protected Element config_info = null; // the xml from the config file
70
71 protected MacroResolver macro_resolver = null;
72
73 /**
74 * the default document type - use if all documents are the same type
75 */
76 protected String default_document_type = null;
77
78 /** constructor */
79 protected AbstractBrowse()
80 {
81 }
82
83 /** configure this service */
84 public boolean configure(Element info, Element extra_info)
85 {
86 if (!super.configure(info, extra_info))
87 {
88 return false;
89 }
90
91 logger.info("Configuring AbstractBrowse...");
92 this.config_info = info;
93 if (macro_resolver != null)
94 {
95 macro_resolver.setSiteDetails(this.site_http_address, this.cluster_name, this.getLibraryName());
96 // set up the macro resolver
97 Element replacement_elem = (Element) GSXML.getChildByTagName(extra_info, GSXML.REPLACE_ELEM + GSXML.LIST_MODIFIER);
98 if (replacement_elem != null)
99 {
100 macro_resolver.addMacros(replacement_elem);
101 }
102
103 // look for any refs to global replace lists
104 NodeList replace_refs_elems = extra_info.getElementsByTagName(GSXML.REPLACE_ELEM + GSXML.LIST_MODIFIER + GSXML.REF_MODIFIER);
105 for (int i = 0; i < replace_refs_elems.getLength(); i++)
106 {
107 String id = ((Element) replace_refs_elems.item(i)).getAttribute("id");
108 if (!id.equals(""))
109 {
110 Element replace_list = GSXML.getNamedElement(this.router.config_info, GSXML.REPLACE_ELEM + GSXML.LIST_MODIFIER, "id", id);
111 if (replace_list != null)
112 {
113 macro_resolver.addMacros(replace_list);
114 }
115 }
116 }
117 }
118
119
120
121 // check that there are classifiers specified
122 Element class_list = (Element) GSXML.getChildByTagName(info, GSXML.CLASSIFIER_ELEM + GSXML.LIST_MODIFIER);
123 if (class_list == null)
124 {
125 // no classifiers specified
126 return false;
127 }
128
129 // get the display and format elements from the coll config file for
130 // the classifiers
131 extractExtraClassifierInfo(info, extra_info);
132
133 // short_service_info_ - the browse one
134 Element cb_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
135 cb_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_BROWSE);
136 cb_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_SERVICE);
137 this.short_service_info.appendChild(cb_service);
138
139 // metadata retrieval for the browsing
140 Element cbmr_service = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
141 cbmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
142 cbmr_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_METADATA_SERVICE);
143 this.short_service_info.appendChild(cbmr_service);
144
145 // the format info
146 Element cb_format_info = this.desc_doc.createElement(GSXML.FORMAT_ELEM);
147 boolean format_found = false;
148
149 // try the default format first
150 Element def_format = (Element) GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM);
151 if (def_format != null)
152 {
153 cb_format_info.appendChild(GSXML.duplicateWithNewName(this.desc_doc, def_format, GSXML.DEFAULT_ELEM, true));
154 format_found = true;
155 }
156
157 // add in to the description a simplified list of classifiers
158 NodeList classifiers = class_list.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
159 for (int i = 0; i < classifiers.getLength(); i++)
160 {
161 Element cl = (Element) classifiers.item(i);
162
163 Element new_cl = (Element) this.desc_doc.importNode(cl, false); // just import this node, not the children
164
165 // get the format info out, and put inside a classifier element
166 Element format_cl = (Element) new_cl.cloneNode(false);
167 Element format = (Element) GSXML.getChildByTagName(cl, GSXML.FORMAT_ELEM);
168 if (format != null)
169 {
170 //copy all the children
171 NodeList elems = format.getChildNodes();
172 for (int j = 0; j < elems.getLength(); j++)
173 {
174 format_cl.appendChild(this.desc_doc.importNode(elems.item(j), true));
175 }
176 cb_format_info.appendChild(format_cl);
177 format_found = true;
178 }
179
180 }
181
182 if (format_found)
183 {
184 this.format_info_map.put(CLASSIFIER_SERVICE, cb_format_info);
185 }
186
187 // look for document display format - is there a default doc type??
188 String path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
189 Element display_format = (Element) GSXML.getNodeByPath(extra_info, path);
190 if (display_format != null)
191 {
192 // check for docType option.
193 Element doc_type_opt = GSXML.getNamedElement(display_format, "gsf:option", GSXML.NAME_ATT, "documentType");
194 if (doc_type_opt != null)
195 {
196 String value = doc_type_opt.getAttribute(GSXML.VALUE_ATT);
197 if (!value.equals(""))
198 {
199 this.default_document_type = value;
200 }
201 }
202 }
203
204 // Base line for document (might be overriden by sub-classes)
205 gs_doc = new BasicDocument(this.default_document_type);
206
207 return true;
208 }
209
210 protected Element getServiceDescription(Document doc, String service_id, String lang, String subset)
211 {
212
213 if (service_id.equals(CLASSIFIER_SERVICE))
214 {
215
216 Element class_list = (Element) GSXML.getChildByTagName(this.config_info, GSXML.CLASSIFIER_ELEM + GSXML.LIST_MODIFIER);
217 if (class_list == null)
218 {
219 // no classifiers specified
220 return null;
221 }
222
223 Element cb_service = doc.createElement(GSXML.SERVICE_ELEM);
224 cb_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_BROWSE);
225 cb_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_SERVICE);
226 cb_service.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_NAME, getTextString(CLASSIFIER_SERVICE + ".name", lang)));
227 cb_service.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(CLASSIFIER_SERVICE + ".description", lang)));
228
229 Element cl_list = doc.createElement(GSXML.CLASSIFIER_ELEM + GSXML.LIST_MODIFIER);
230 cb_service.appendChild(cl_list);
231 NodeList classifiers = class_list.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
232 for (int i = 0; i < classifiers.getLength(); i++)
233 {
234 Element cl = (Element) classifiers.item(i);
235 Element new_cl = (Element) doc.importNode(cl, false); // just import this node, not the children
236 cl_list.appendChild(new_cl);
237
238 // have we got a displayItem for the classifier title?
239 String text = getDisplayText(cl, GSXML.DISPLAY_TEXT_NAME, lang, "en", "metadata_names");
240 //get the classify title from the database
241 String class_id = cl.getAttribute(GSXML.NAME_ATT);
242 String content = getMetadata(class_id, "Title");
243 if (text == null || text.equals("")) {
244
245 // no display element was specified, use the metadata name
246 if (!content.equals("")) {
247
248 text = getTextString(content + ".buttonname", lang, "metadata_names");
249 if (text == null) {
250
251 text = content;
252 }
253 }
254
255 if (text == null) {
256 text=class_id;
257 }
258 }
259 Element cl_name = GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_NAME, text);
260 new_cl.appendChild(cl_name);
261
262 // description
263
264 String meta_name = getTextString(content, lang, "metadata_names");
265 if (meta_name == null)
266 {
267 meta_name = content;
268 }
269 String[] array = { meta_name };
270 String description = getTextString("ClassifierBrowse.classifier_help", lang, array);
271 Element cl_desc = GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_DESCRIPTION, description);
272 new_cl.appendChild(cl_desc);
273
274 }
275 return cb_service;
276 }
277
278 // these ones are probably never called, but put them here just in case
279
280 if (service_id.equals(CLASSIFIER_METADATA_SERVICE))
281 {
282
283 Element cbmr_service = doc.createElement(GSXML.SERVICE_ELEM);
284 cbmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
285 cbmr_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_METADATA_SERVICE);
286 return cbmr_service;
287 }
288
289 return null;
290 }
291
292 /**
293 * this looks for any classifier specific display or format info from
294 * extra_info and adds it in to the correct place in info
295 */
296 static boolean extractExtraClassifierInfo(Element info, Element extra_info)
297 {
298 if (extra_info == null)
299 {
300 return false;
301 }
302
303 Document owner = info.getOwnerDocument();
304 // so far we have display and format elements that we need for classifiers
305 NodeList classifiers = info.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
306 Element config_browse = (Element) GSXML.getChildByTagName(extra_info, GSXML.BROWSE_ELEM);
307
308 for (int i = 0; i < classifiers.getLength(); i++)
309 {
310 Element cl = (Element) classifiers.item(i);
311 String name = cl.getAttribute(GSXML.NAME_ATT);
312
313 //Element node_extra = GSXML.getNamedElement(config_browse,
314 // GSXML.CLASSIFIER_ELEM,
315 // GSXML.NAME_ATT,
316 // name);
317 //now use the position to get the node - CL1
318 // assumes the same number of classifiers in collectionCOnfig as in buildConfig
319 // int position = Integer.parseInt(name.substring(2));
320
321 Element node_extra = null;
322 NodeList cls = config_browse.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
323 //if (position >0 && position <= cls.getLength()) {
324 // node_extra = (Element) cls.item((position -1));
325 //}
326 if (i < cls.getLength())
327 {
328 node_extra = (Element) cls.item(i);
329 }
330
331 if (node_extra == null)
332 {
333 logger.error("GS2REtrieve: haven't found extra info for classifier named " + name);
334 continue;
335 }
336
337 // get the display elements if any - displayName
338 NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
339 if (display_names != null)
340 {
341 Element display = owner.createElement(GSXML.DISPLAY_ELEM);
342 for (int j = 0; j < display_names.getLength(); j++)
343 {
344 Element e = (Element) display_names.item(j);
345 cl.appendChild(owner.importNode(e, true));
346 }
347 }
348
349 // get the format element if any
350 Element format = (Element) GSXML.getChildByTagName(node_extra, GSXML.FORMAT_ELEM);
351 if (format != null)
352 { // append to index info
353 cl.appendChild(owner.importNode(format, true));
354 }
355 } // for each classifier
356
357 // now check for default format info
358 Element default_format = (Element) GSXML.getChildByTagName(config_browse, GSXML.FORMAT_ELEM);
359 if (default_format != null)
360 { // append to info
361 info.appendChild(owner.importNode(default_format, true));
362 }
363
364 return true;
365 }
366
367 protected Element processClassifierBrowse(Element request)
368 {
369
370 // Create a new (empty) result message
371 Document result_doc = XMLConverter.newDOM();
372 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
373 result.setAttribute(GSXML.FROM_ATT, CLASSIFIER_SERVICE);
374 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
375
376 String lang = request.getAttribute(GSXML.LANG_ATT);
377 Element query_node_list = (Element) GSXML.getChildByTagName(request, GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
378 if (query_node_list == null)
379 {
380 logger.error(" ClassifierBrowse request specified no classifier nodes.\n");
381 return result;
382 }
383
384 // Get the parameters of the request
385 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
386 if (param_list == null)
387 {
388 logger.error(" ClassifierBrowse request had no paramList.");
389 return result; // Return the empty result
390 }
391
392 // the type of info required
393 boolean want_structure = false;
394 boolean want_info = false;
395
396 ArrayList<String> info_types = new ArrayList<String>();
397 // The document structure information desired
398 boolean want_ancestors = false;
399 boolean want_parent = false;
400 boolean want_siblings = false;
401 boolean want_children = false;
402 boolean want_descendants = false;
403
404 boolean want_entire_structure = false;
405 // Process the request parameters
406 NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
407 for (int i = 0; i < params.getLength(); i++)
408 {
409
410 Element param = (Element) params.item(i);
411 String p_name = param.getAttribute(GSXML.NAME_ATT);
412 String p_value = GSXML.getValue(param);
413 // Identify the structure information desired
414 if (p_name.equals(STRUCT_PARAM))
415 {
416 want_structure = true;
417
418 // This is NOT locale sensitive
419 if (p_value.equals(STRUCT_ANCESTORS))
420 want_ancestors = true;
421 else if (p_value.equals(STRUCT_PARENT))
422 want_parent = true;
423 else if (p_value.equals(STRUCT_SIBS))
424 want_siblings = true;
425 else if (p_value.equals(STRUCT_CHILDREN))
426 want_children = true;
427 else if (p_value.equals(STRUCT_DESCENDS))
428 want_descendants = true;
429 else if (p_value.equals(STRUCT_ENTIRE))
430 want_entire_structure = true;
431 else
432 logger.error("AbstractDocumentRetrieve Warning: Unknown value \"" + p_value + "\".");
433 }
434 else if (p_name.equals(INFO_PARAM))
435 {
436 want_info = true;
437 info_types.add(p_value);
438 }
439 }
440
441 // Make sure there is no repeated information
442 if (want_ancestors)
443 want_parent = false;
444 if (want_descendants)
445 want_children = false;
446
447 // the node list to hold the results
448 Element node_list = result_doc.createElement(GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
449 result.appendChild(node_list);
450
451 // Get the nodes
452 String[] node_ids = GSXML.getAttributeValuesFromList(query_node_list, GSXML.NODE_ID_ATT);
453 for (int i = 0; i < node_ids.length; i++)
454 {
455 // Add the document to the list
456 Element node = result_doc.createElement(GSXML.CLASS_NODE_ELEM);
457 node_list.appendChild(node);
458
459 String node_id = node_ids[i];
460 node.setAttribute(GSXML.NODE_ID_ATT, node_id);
461
462 if (idNeedsTranslating(node_id))
463 {
464 node_id = translateId(node_id);
465 if (node_id == null)
466 {
467 continue;
468 }
469 node.setAttribute(GSXML.NODE_ID_ATT, node_id);
470 }
471
472 if (want_info)
473 {
474 Element node_info_elem = result_doc.createElement("nodeStructureInfo");
475 node.appendChild(node_info_elem);
476
477 for (int j = 0; j < info_types.size(); j++)
478 {
479 String info_type = info_types.get(j);
480 String info_value = getStructureInfo(node_id, info_type);
481 if (info_value != null)
482 {
483 Element info_elem = result_doc.createElement("info");
484 info_elem.setAttribute(GSXML.NAME_ATT, info_type);
485 info_elem.setAttribute(GSXML.VALUE_ATT, info_value);
486 node_info_elem.appendChild(info_elem);
487 }
488 }
489 }
490
491 if (want_structure)
492 {
493 // all structure info goes into a nodeStructure elem
494 Element structure_elem = result_doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
495 node.appendChild(structure_elem);
496
497 if (want_entire_structure)
498 {
499 String root_id = getRootId(node_id);
500 Element root_node = createClassifierNode(result_doc, root_id); //, true, false);
501 addDescendants(root_node, root_id, true);
502 structure_elem.appendChild(root_node);
503 continue; // with the next document, we dont need to do any more here
504 }
505
506 // Add the requested structure information
507 Element base_node = createClassifierNode(result_doc, node_id); //, false, false);
508
509 //Ancestors: continually add parent nodes until the root is reached
510 Element top_node = base_node; // the top node so far
511 if (want_ancestors)
512 {
513 String current_id = node_id;
514 while (true)
515 {
516 String parent_id = getParentId(current_id);
517 //Element parent = getParent(current_id);
518 if (parent_id == null)
519 break; // no parent
520 Element parent_node = createClassifierNode(result_doc, parent_id);
521 parent_node.appendChild(top_node);
522 current_id = parent_id;//.getAttribute(GSXML.NODE_ID_ATT);
523 top_node = parent_node;
524 }
525 }
526 // Parent: get the parent of the selected node
527 else if (want_parent)
528 {
529 String parent_id = getParentId(node_id);
530 if (parent_id != null)
531 {
532 Element parent_node = createClassifierNode(result_doc, parent_id);
533 parent_node.appendChild(base_node);
534 top_node = parent_node;
535 }
536 }
537
538 // now the top node is the root of the structure
539 structure_elem.appendChild(top_node);
540
541 //Siblings: get the other descendants of the selected node's parent
542 if (want_siblings)
543 {
544
545 Element parent_node = (Element) base_node.getParentNode(); // this may be the structure element if there has been no request for parents or ancestors
546 String parent_id = getParentId(node_id);
547 // add siblings, - returns a pointer to the new current node
548 base_node = addSiblings(parent_node, parent_id, node_id);
549 }
550
551 // Children: get the descendants, but only one level deep
552 if (want_children)
553 {
554 addDescendants(base_node, node_id, false);
555 }
556 // Descendants: recursively get every descendant
557 else if (want_descendants)
558 {
559 addDescendants(base_node, node_id, true);
560 }
561
562 NodeList classifierElements = result.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
563 for (int j = 0; j < classifierElements.getLength(); j++)
564 {
565 Element current = (Element) classifierElements.item(j);
566 Node parentNode = current.getParentNode();
567
568 if (parentNode == null)
569 {
570 continue;
571 }
572
573 Element parent = (Element) parentNode;
574 String childType = parent.getAttribute(GSXML.CHILD_TYPE_ATT);
575 if (childType == null || childType.length() == 0)
576 {
577 continue;
578 }
579
580 current.setAttribute(GSXML.CLASSIFIER_STYLE_ATT, childType);
581 }
582 } // if want structure
583 } // for each doc
584 return result;
585 }
586
587 protected Element processClassifierBrowseMetadataRetrieve(Element request)
588 {
589
590 // Create a new (empty) result message
591 Document result_doc = XMLConverter.newDOM();
592 Element result = result_doc.createElement(GSXML.RESPONSE_ELEM);
593
594 String lang = request.getAttribute(GSXML.LANG_ATT);
595 result.setAttribute(GSXML.FROM_ATT, CLASSIFIER_METADATA_SERVICE);
596 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
597
598 // Get the parameters of the request
599 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
600 if (param_list == null)
601 {
602 logger.error("AbstractBrowse, ClassifierBrowseMetadataRetrieve Error: missing paramList.\n");
603 return result; // Return the empty result
604 }
605
606 // The metadata information required
607 ArrayList<String> metadata_names_list = new ArrayList<String>();
608 boolean all_metadata = false;
609 // Process the request parameters
610 Element param = GSXML.getFirstElementChild(param_list);//(Element) param_list.getFirstChild();
611 while (param != null)
612 {
613 // Identify the metadata information desired
614 if (param.getAttribute(GSXML.NAME_ATT).equals("metadata"))
615 {
616 String metadata = GSXML.getValue(param);
617 if (metadata.equals("all"))
618 {
619 all_metadata = true;
620 break;
621 }
622 metadata_names_list.add(metadata);
623 }
624 param = (Element) param.getNextSibling();
625 }
626
627 Element node_list = result_doc.createElement(GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
628 result.appendChild(node_list);
629
630 // Get the nodes
631 Element request_node_list = (Element) GSXML.getChildByTagName(request, GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
632 if (request_node_list == null)
633 {
634 logger.error(" ClassifierBrowseMetadataRetrieve request had no " + GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
635 return result;
636 }
637
638 NodeList request_nodes = request_node_list.getChildNodes();
639 for (int i = 0; i < request_nodes.getLength(); i++)
640 {
641 Element request_node = (Element) request_nodes.item(i);
642 String node_id = request_node.getAttribute(GSXML.NODE_ID_ATT);
643
644 // Add the document to the results list
645 Element new_node = (Element) result_doc.importNode(request_node, false);
646 node_list.appendChild(new_node);
647
648 if (idNeedsTranslating(node_id))
649 {
650 node_id = translateId(node_id);
651 }
652 if (node_id == null)
653 {
654 continue;
655 }
656
657 Element metadata_list = getMetadataList(result_doc, node_id, all_metadata, metadata_names_list);
658 new_node.appendChild(metadata_list);
659 }
660
661 return result;
662 }
663
664 /** Creates a classifier node */
665 protected Element createClassifierNode(Document doc, String node_id)
666 {
667 Element node = doc.createElement(GSXML.CLASS_NODE_ELEM);
668 node.setAttribute(GSXML.NODE_ID_ATT, node_id);
669 node.setAttribute(GSXML.CHILD_TYPE_ATT, getChildType(node_id));
670 return node;
671 }
672
673 /**
674 * create an element to go into the structure. A node element has the form
675 * <docNode nodeId='xxx' nodeType='leaf' docType='hierarchy'/>
676 */
677 protected Element createDocNode(Document doc, String node_id)
678 {
679 return this.gs_doc.createDocNode(doc, node_id);
680 }
681
682 /**
683 * returns the node type of the specified node. should be one of
684 * GSXML.NODE_TYPE_LEAF, GSXML.NODE_TYPE_INTERNAL, GSXML.NODE_TYPE_ROOT
685 */
686 protected String getNodeType(String node_id, String doc_type)
687 {
688 return this.gs_doc.getNodeType(node_id, doc_type);
689 }
690
691 /**
692 * adds all the children of doc_id the the doc element, and if
693 * recursive=true, adds all their children as well
694 */
695 protected void addDescendants(Element node, String node_id, boolean recursive)
696 {
697 ArrayList<String> child_ids = getChildrenIds(node_id);
698 String[] offsets = getMDOffsets(node_id);
699 if (child_ids == null)
700 return;
701 Document doc = node.getOwnerDocument();
702 if (offsets != null && child_ids.size() != offsets.length) {
703 offsets = null; // something is wrong, they should be the same length
704 }
705 for (int i = 0; i < child_ids.size(); i++)
706 {
707 String child_id = child_ids.get(i);
708 Element child_elem;
709 if (isDocumentId(child_id))
710 {
711 child_elem = createDocNode(doc, child_id);
712 if (offsets != null) {
713 child_elem.setAttribute("mdoffset", offsets[i]);
714 }
715 }
716 else
717 {
718 child_elem = createClassifierNode(doc, child_id);
719 }
720 node.appendChild(child_elem);
721 if (recursive)
722 {
723 addDescendants(child_elem, child_id, recursive);
724 }
725 }
726 }
727
728 /**
729 * adds all the siblings of current_id to the parent element. returns the
730 * new current element
731 */
732 protected Element addSiblings(Element parent_node, String parent_id, String current_id)
733 {
734 Element current_node = GSXML.getFirstElementChild(parent_node);//(Element)parent_node.getFirstChild();
735 if (current_node == null)
736 {
737 // create a sensible error message
738 logger.error(" there should be a first child.");
739 return null;
740 }
741 // remove the current child,- will add it in later in its correct place
742 parent_node.removeChild(current_node);
743
744 // add in all the siblings,- might be classifier/document nodes
745 addDescendants(parent_node, parent_id, false);
746
747 // find the node that is now the current node
748 // this assumes that the new node that was created is the same as
749 // the old one that was removed - we may want to replace the new one
750 // with the old one.
751 Element new_current = GSXML.getNamedElement(parent_node, current_node.getNodeName(), GSXML.NODE_ID_ATT, current_id);
752 return new_current;
753
754 }
755
756 /**
757 * returns true if oid ends in .fc (firstchild), .lc (lastchild), .pr
758 * (parent), .ns (next sibling), .ps (prev sibling), .rt (root) .ss
759 * (specified sibling), false otherwise
760 */
761 protected boolean idNeedsTranslating(String node_id)
762 {
763 return OID.needsTranslating(node_id);
764 }
765
766 /** returns the list of sibling ids, including the specified node_id */
767 protected ArrayList<String> getSiblingIds(String node_id)
768 {
769 return this.gs_doc.getSiblingIds(node_id);
770 }
771
772 /** if id ends in .fc, .pc etc, then translate it to the correct id */
773 abstract protected String translateId(String node_id);
774
775 /** Gets the type of list a classifier is (e.g. VList or HList) */
776 abstract protected String getChildType(String node_id);
777
778 /**
779 * returns the document type of the doc that the specified node belongs to.
780 * should be one of GSXML.DOC_TYPE_SIMPLE, GSXML.DOC_TYPE_PAGED,
781 * GSXML.DOC_TYPE_HIERARCHY
782 */
783 protected String getDocType(String node_id) {
784 return this.gs_doc.getDocType(node_id);
785 }
786
787 /**
788 * returns the id of the root node of the document containing node node_id.
789 * . may be the same as node_id
790 */
791 protected String getRootId(String node_id) {
792 return this.gs_doc.getRootId(node_id);
793 }
794
795 /** returns a list of the child ids in order, null if no children */
796 protected ArrayList<String> getChildrenIds(String node_id) {
797 return this.gs_doc.getChildrenIds(node_id);
798 }
799
800 protected String[] getMDOffsets(String node_id) {
801
802 String offset_str = this.gs_doc.getMetadata(node_id, "mdoffset");
803 if (offset_str.equals("")) {
804 return null;
805 }
806 return offset_str.split(";"); //, -1); // use -1 limit to get trailing empty strings
807 }
808 /** returns the node id of the parent node, null if no parent */
809 protected String getParentId(String node_id) {
810 return this.gs_doc.getParentId(node_id);
811 }
812
813 /**
814 * returns true if the id refers to a document (rather than a classifier
815 * node)
816 */
817 abstract protected boolean isDocumentId(String node_id);
818
819 /**
820 * get the metadata for the classifier node node_id returns a metadataList
821 * element: <metadataList><metadata
822 * name="xxx">value</metadata></metadataList> if all_metadata is true,
823 * returns all available metadata, otherwise just returns requested metadata
824 */
825 abstract protected Element getMetadataList(Document doc, String node_id, boolean all_metadata, ArrayList<String> metadata_names);
826
827 /**
828 * get the particular metadata (identified by the metadata name) for the
829 * classifier node node_id
830 *
831 */
832 abstract protected String getMetadata(String node_id, String metadata_name);
833
834 /**
835 * returns the structural information asked for. info_type may be one of
836 * INFO_NUM_SIBS, INFO_NUM_CHILDREN, INFO_SIB_POS, INFO_DOC_TYPE
837 */
838 protected String getStructureInfo(String node_id, String info_type) {
839 return this.gs_doc.getStructureInfo(node_id, info_type);
840 }
841
842}
Note: See TracBrowser for help on using the repository browser.