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

Last change on this file since 29090 was 29090, checked in by kjdon, 10 years ago

added code for setting mdoffset attributes for docNodes in a classifier. Can be used to display the correct metadata value for the documents position in the classifier list

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