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

Last change on this file since 38154 was 38019, checked in by kjdon, 9 months ago

removing the bit where the buttonname for a classifier is used for a dictionary lookup. THis is not transparent, and hard to work out what is going on. So now, button name will be used as is. If you want dictionary lookups, use <displayItem name='name' key='Title.buttonname'/> instead

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