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

Last change on this file was 38966, checked in by anupama, 34 hours ago

In commit r 22306, I had made the AbstractBrowse protected method extractExtraClassifierInfo() static, because it wasn't using any member variables or methods and class FedoraServiceProxy (which wasn't a subclass of AbstractBrowse but only of shared superclass ServiceRack) needed to use it in entirety. This produced headscratching 14 years later as to why it was a static function of AbstractBrowse and not a regular method, as there was briefly interest in overriding the functionality in GS2Browse. Dr Bainbridge said it should become a static utility method as it was too long to justify 2 copies of the code floating around and Kathy suggested moving it into GSXML.java.

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