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

Last change on this file since 31867 was 31867, checked in by kjdon, 7 years ago

setting classifier style attribute - can't remember why! Also, need to set teh class loader for the macro resolver AFTER the class loader is constructedsvn diff util/GSXML.java

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