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

Last change on this file since 30631 was 29989, checked in by kjdon, 9 years ago

add in the replaceListRef macros to the macro resolver

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