source: trunk/gsdl3/src/java/org/greenstone/gsdl3/service/GS2Retrieve.java@ 8690

Last change on this file since 8690 was 8690, checked in by kjdon, 19 years ago

check the doctype in gdbm db first, before trying to work it out.

  • Property svn:keywords set to Author Date Id Revision
File size: 34.7 KB
Line 
1/*
2 * GS2Retrieve.java
3 * Copyright (C) 2002 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
22// Greenstone classes
23import org.greenstone.gdbm.*;
24import org.greenstone.gsdl3.util.*;
25
26// XML classes
27import org.w3c.dom.Document;
28import org.w3c.dom.Element;
29import org.w3c.dom.NodeList;
30
31// General Java classes
32import java.io.File;
33import java.util.StringTokenizer;
34import java.util.Vector;
35import java.util.Set;
36import java.util.Iterator;
37import java.util.ArrayList;
38
39/** Implements the generic retrieval and classifier services for GS2
40 * collections.
41 *
42 * @author <a href="mailto:[email protected]">Katherine Don</a>
43 * @author <a href="mailto:[email protected]">Michael Dewsnip</a>
44 * @version $Revision: 8690 $
45 */
46
47public abstract class GS2Retrieve
48 extends ServiceRack {
49
50 // the services on offer
51 // these strings must match what is found in the properties file
52 protected static final String DOCUMENT_STRUCTURE_RETRIEVE_SERVICE = "DocumentStructureRetrieve";
53 protected static final String DOCUMENT_METADATA_RETRIEVE_SERVICE = "DocumentMetadataRetrieve";
54 protected static final String DOCUMENT_CONTENT_RETRIEVE_SERVICE = "DocumentContentRetrieve";
55
56
57 // the browsing services - now in here, these will only be advertised if classifiers have been specified in the config file
58 private static final String CLASSIFIER_SERVICE = "ClassifierBrowse";
59 private static final String CLASSIFIER_METADATA_SERVICE = "ClassifierBrowseMetadataRetrieve";
60
61 protected static final String STRUCT_PARAM = "structure";
62 protected static final String INFO_PARAM = "info";
63
64 protected static final String STRUCT_ANCESTORS = "ancestors";
65 protected static final String STRUCT_PARENT = "parent";
66 protected static final String STRUCT_SIBS = "siblings";
67 protected static final String STRUCT_CHILDREN = "children";
68 protected static final String STRUCT_DESCENDS = "descendants";
69 protected static final String STRUCT_ENTIRE = "entire";
70
71 protected static final String INFO_NUM_SIBS = "numSiblings";
72 protected static final String INFO_NUM_CHILDREN = "numChildren";
73 protected static final String INFO_SIB_POS = "siblingPosition";
74
75 protected static final String EXTLINK_PARAM = "ext";
76
77 protected static final int DOCUMENT=1;
78 protected static final int CLASSIFIER=2;
79
80 protected GDBMWrapper gdbm_src = null;
81 protected Element config_info = null; // the xml from the config file
82
83 protected GS2MacroResolver macro_resolver = null;
84
85 /** constructor */
86 protected GS2Retrieve()
87 {
88 this.gdbm_src = new GDBMWrapper();
89 this.macro_resolver = new GS2MacroResolver(gdbm_src);
90 }
91
92
93 /** configure this service */
94 public boolean configure(Element info, Element extra_info)
95 {
96 System.out.println("Configuring GS2Retrieve...");
97 this.config_info = info;
98
99 // set up short_service_info_ - for now just has name and type
100 Element dsr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
101 dsr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
102 dsr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_STRUCTURE_RETRIEVE_SERVICE);
103 this.short_service_info.appendChild(dsr_service);
104
105 Element dmr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
106 dmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
107 dmr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_METADATA_RETRIEVE_SERVICE);
108 this.short_service_info.appendChild(dmr_service);
109
110 Element dcr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
111 dcr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
112 dcr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_CONTENT_RETRIEVE_SERVICE);
113 this.short_service_info.appendChild(dcr_service);
114
115 // Open GDBM database for querying
116 String gdbm_db_file = GSFile.GDBMDatabaseFile(this.site_home, this.cluster_name);
117 if (!this.gdbm_src.openDatabase(gdbm_db_file, GDBMWrapper.READER)) {
118 System.err.println("GS2Retrieve Error: Could not open GDBM database!");
119 return false;
120 }
121
122 // look for document display format
123 String path = GSPath.appendLink(GSXML.DISPLAY_ELEM, GSXML.FORMAT_ELEM);
124 Element display_format = (Element)GSXML.getNodeByPath(extra_info, path);
125 if (display_format != null) {
126 this.format_info_map.put(DOCUMENT_CONTENT_RETRIEVE_SERVICE, this.doc.importNode(display_format, true));
127 // shoudl we make a copy?
128 }
129
130 // set up the macro resolver
131 Element replacement_elem = (Element)GSXML.getChildByTagName(extra_info, "replaceList");
132 if (replacement_elem != null) {
133 NodeList replaces = replacement_elem.getElementsByTagName("replace");
134 for (int i=0; i<replaces.getLength(); i++) {
135 Element e = (Element)replaces.item(i);
136 String scope = e.getAttribute("scope");
137 if (scope.equals("")) {
138 scope = GS2MacroResolver.SCOPE_ALL;
139 }
140 String from = e.getAttribute("macro");
141 String to = e.getAttribute("text");
142 if (!to.equals("")) {
143 macro_resolver.addMacro(GS2MacroResolver.TYPE_TEXT, from, to, scope);
144 } else {
145 String meta = e.getAttribute("metadata");
146 if (!meta.equals("")) {
147 macro_resolver.addMacro(GS2MacroResolver.TYPE_META, from, meta, scope);
148 } else {
149 String key = e.getAttribute("key");
150 String bundle = e.getAttribute("bundle");
151 macro_resolver.addMacro(GS2MacroResolver.TYPE_DICT, from, bundle, key, scope);
152 }
153 }
154 }
155 }
156
157 // now do the classifier browse service
158
159 // check that there are classifiers specified
160 Element class_list = (Element)GSXML.getChildByTagName(info, GSXML.CLASSIFIER_ELEM+GSXML.LIST_MODIFIER);
161 if (class_list == null) {
162 // no classifiers specified
163 return true;
164 }
165
166 // get the display and format elements from the coll config file for
167 // the classifiers
168 extractExtraClassifierInfo(info, extra_info);
169
170 this.config_info = info;
171
172 // short_service_info_ - the browse one
173 Element cb_service = this.doc.createElement(GSXML.SERVICE_ELEM);
174 cb_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_BROWSE);
175 cb_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_SERVICE);
176 this.short_service_info.appendChild(cb_service);
177
178 // metadata retrieval for the browsing
179 Element cbmr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
180 cbmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
181 cbmr_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_METADATA_SERVICE);
182 this.short_service_info.appendChild(cbmr_service);
183
184 // the format info
185 Element cb_format_info = this.doc.createElement(GSXML.FORMAT_ELEM);
186 boolean format_found = false;
187
188 // try the default format first
189 Element def_format = (Element) GSXML.getChildByTagName(info, GSXML.FORMAT_ELEM);
190 if (def_format != null) {
191 cb_format_info.appendChild(GSXML.duplicateWithNewName(this.doc, def_format, GSXML.DEFAULT_ELEM, true));
192 format_found = true;
193 }
194
195 // add in to the description a simplified list of classifiers
196 NodeList classifiers = class_list.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
197 for(int i=0; i<classifiers.getLength(); i++) {
198 Element cl = (Element)classifiers.item(i);
199 Element new_cl = (Element)this.doc.importNode(cl, false); // just import this node, not the children
200
201 // get the format info out, and put inside a classifier element
202 Element format_cl = (Element)new_cl.cloneNode(false);
203 Element format = (Element)GSXML.getChildByTagName(cl, GSXML.FORMAT_ELEM);
204 if (format != null) {
205
206 //copy all the children
207 NodeList elems = format.getChildNodes();
208 for (int j=0; j<elems.getLength();j++) {
209 format_cl.appendChild(this.doc.importNode(elems.item(j), true));
210 }
211 cb_format_info.appendChild(format_cl);
212 format_found = true;
213 }
214
215
216 }
217
218 if (format_found) {
219 this.format_info_map.put(CLASSIFIER_SERVICE, cb_format_info);
220 }
221
222 return true;
223 }
224
225 protected Element getServiceDescription(String service_id, String lang, String subset) {
226
227 if (service_id.equals(CLASSIFIER_SERVICE)) {
228
229 Element class_list = (Element)GSXML.getChildByTagName(this.config_info, GSXML.CLASSIFIER_ELEM+GSXML.LIST_MODIFIER);
230 if (class_list == null) {
231 // no classifiers specified
232 return null;
233 }
234
235 Element cb_service = this.doc.createElement(GSXML.SERVICE_ELEM);
236 cb_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_BROWSE);
237 cb_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_SERVICE);
238 cb_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, getTextString(CLASSIFIER_SERVICE+".name", lang)));
239 cb_service.appendChild(GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(CLASSIFIER_SERVICE+".description", lang)));
240
241 Element cl_list = this.doc.createElement(GSXML.CLASSIFIER_ELEM+GSXML.LIST_MODIFIER);
242 cb_service.appendChild(cl_list);
243 NodeList classifiers = class_list.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
244 for(int i=0; i<classifiers.getLength(); i++) {
245 Element cl = (Element)classifiers.item(i);
246 Element new_cl = (Element)this.doc.importNode(cl, false); // just import this node, not the children
247 String content = cl.getAttribute(GSXML.CLASSIFIER_CONTENT_ATT);
248 cl_list.appendChild(new_cl);
249 String text = GSXML.getDisplayText(cl,
250 GSXML.DISPLAY_TEXT_NAME,
251 lang, "en");
252 if (text == null || text.equals("")) {
253 // no display element was specified, use the metadata name
254 // for now this looks in the class properties file
255 // this needs to use a general metadata thing instead
256 text = getMetadataNameText(content+".buttonname", lang);
257 }
258 if (text == null) {
259 text = content;
260 }
261
262 Element cl_name = GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_NAME, text);
263 new_cl.appendChild(cl_name);
264
265 // description
266
267 String meta_name = getMetadataNameText(content, lang);
268 if (meta_name==null) {
269 meta_name = content;
270 }
271 String [] array = {meta_name};
272 String description = getTextString("ClassifierBrowse.classifier_help", array, lang);
273 Element cl_desc = GSXML.createDisplayTextElement(this.doc, GSXML.DISPLAY_TEXT_DESCRIPTION, description);
274 new_cl.appendChild(cl_desc);
275
276 }
277 return cb_service;
278 }
279
280 // these ones are probably never called, but put them here just in case
281
282 if (service_id.equals(CLASSIFIER_METADATA_SERVICE)) {
283
284 Element cbmr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
285 cbmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
286 cbmr_service.setAttribute(GSXML.NAME_ATT, CLASSIFIER_METADATA_SERVICE);
287 return cbmr_service;
288 }
289
290 if (service_id.equals(DOCUMENT_STRUCTURE_RETRIEVE_SERVICE)) {
291 Element dsr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
292 dsr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
293 dsr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_STRUCTURE_RETRIEVE_SERVICE);
294 return dsr_service;
295 }
296 if (service_id.equals(DOCUMENT_METADATA_RETRIEVE_SERVICE)) {
297 Element dmr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
298 dmr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
299 dmr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_METADATA_RETRIEVE_SERVICE);
300 return dmr_service;
301 }
302
303 if (service_id.equals(DOCUMENT_CONTENT_RETRIEVE_SERVICE)) {
304 Element dcr_service = this.doc.createElement(GSXML.SERVICE_ELEM);
305 dcr_service.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_RETRIEVE);
306 dcr_service.setAttribute(GSXML.NAME_ATT, DOCUMENT_CONTENT_RETRIEVE_SERVICE);
307 return dcr_service;
308 }
309
310 return null;
311 }
312
313 /** this looks for any classifier specific display or format info from extra_info and adds it in to the correct place in info */
314 protected boolean extractExtraClassifierInfo(Element info, Element extra_info) {
315
316 if (extra_info == null) {
317 return false;
318 }
319
320 Document owner = info.getOwnerDocument();
321 // so far we have display and format elements that we need for classifiers
322 NodeList classifiers = info.getElementsByTagName(GSXML.CLASSIFIER_ELEM);
323 Element config_browse = (Element)GSXML.getChildByTagName(extra_info, GSXML.BROWSE_ELEM);
324
325 for (int i=0; i<classifiers.getLength();i++) {
326 Element cl = (Element)classifiers.item(i);
327 String name = cl.getAttribute(GSXML.NAME_ATT);
328 Element node_extra = GSXML.getNamedElement(config_browse,
329 GSXML.CLASSIFIER_ELEM,
330 GSXML.NAME_ATT,
331 name);
332 if (node_extra == null) {
333 System.err.println("GS2REtrieve: haven't found extra info for classifier named "+name);
334 continue;
335 }
336
337 // get the display elements if any - displayName
338 NodeList display_names = node_extra.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
339 if (display_names !=null) {
340 Element display = owner.createElement(GSXML.DISPLAY_ELEM);
341 for (int j=0; j<display_names.getLength(); j++) {
342 Element e = (Element)display_names.item(j);
343 cl.appendChild(owner.importNode(e, true));
344
345 }
346 }
347
348 // get the format element if any
349 Element format = (Element)GSXML.getChildByTagName(node_extra, GSXML.FORMAT_ELEM);
350 if (format==null) { // try a generic one that applies to all classifiers
351 format = (Element)GSXML.getChildByTagName(extra_info,
352 GSXML.FORMAT_ELEM);
353 }
354 if (format!=null) { // append to index info
355 cl.appendChild(owner.importNode(format, true));
356 }
357 } // for each classifier
358
359 // now check for default format info
360 Element default_format = (Element)GSXML.getChildByTagName(config_browse, GSXML.FORMAT_ELEM);
361 if (default_format!=null) { // append to info
362 info.appendChild(owner.importNode(default_format, true));
363 }
364
365 return true;
366 }
367
368
369 /** parent is true if this node is definitely the parent of something,
370 * child is true is it definitely is a child of something - just for efficiency purposes */
371 protected Element createDocNode(String node_id, boolean parent, boolean child) {
372
373 // create this here or pass it in?
374 DBInfo info = this.gdbm_src.getInfo(node_id);
375 Element node;
376 if (isClassifier(node_id)) {
377 node = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
378 //String childtype = info.getInfo("childtype");
379 //String orientation="";
380 //if (childtype.equals("HList")) {
381 // orientation = "horizontal";
382 //} else { // assume vertical
383 // orientation = "vertical";
384 //}
385 //node.setAttribute(GSXML.CLASS_NODE_ORIENTATION_ATT, orientation);
386 } else {
387
388 node = this.doc.createElement(GSXML.DOC_NODE_ELEM);
389
390 String top_id = OID.getTop(node_id);
391 boolean is_top = (top_id.equals(node_id) ? true : false);
392
393 String children = info.getInfo("contains");
394 boolean is_leaf = (children.equals("") ? true : false);
395
396 // set the node type att
397 if (is_top) {
398 node.setAttribute(GSXML.NODE_TYPE_ATT, GSXML.NODE_TYPE_ROOT);
399 } else if (is_leaf) {
400 node.setAttribute(GSXML.NODE_TYPE_ATT, GSXML.NODE_TYPE_LEAF);
401 } else {
402 node.setAttribute(GSXML.NODE_TYPE_ATT, GSXML.NODE_TYPE_INTERIOR);
403 }
404
405 // set the doc type att
406 String doc_type = info.getInfo("doctype");
407 if (!doc_type.equals("")&&!doc_type.equals("doc")) {
408 node.setAttribute(GSXML.DOC_TYPE_ATT, doc_type);
409 } else {
410 if (is_top && is_leaf) { // a single section document
411 node.setAttribute(GSXML.DOC_TYPE_ATT, "simple");
412
413 } else {
414
415 if (!is_top) { // we need to look at the top info
416 info = this.gdbm_src.getInfo(top_id);
417 }
418
419 String childtype = info.getInfo("childtype");
420 if (childtype.equals("Paged")) {
421 node.setAttribute(GSXML.DOC_TYPE_ATT, "paged");
422 } else {
423 node.setAttribute(GSXML.DOC_TYPE_ATT, "hierarchy");
424 }
425 }
426 }
427
428 }
429 node.setAttribute(GSXML.NODE_ID_ATT, node_id);
430 return node;
431
432 }
433 /** Returns the parent of a specified documentID, or null if none exists */
434 protected Element getParent(String doc_id)
435 {
436 String parent_id = OID.getParent(doc_id);
437 if (parent_id.equals(doc_id))
438 return null;
439
440 return createDocNode(parent_id, true, false);
441 }
442
443
444 /** adds all the children of doc_id the the doc element,
445 * and if recursive=true, adds all their children as well*/
446 protected void addDescendants(Element doc, String doc_id,
447 boolean recursive)
448 {
449 DBInfo info = this.gdbm_src.getInfo(doc_id);
450 String contains = info.getInfo("contains");
451
452 StringTokenizer st = new StringTokenizer(contains, ";");
453 while (st.hasMoreTokens()) {
454 String child_id = st.nextToken().replaceAll("\"", doc_id);
455 Element child = createDocNode(child_id, false, true);
456 doc.appendChild(child);
457
458 // Apply recursively, if desired
459 if (recursive) {
460 addDescendants(child, child_id, recursive);
461 }
462
463 }
464 }
465
466 /** adds all the siblings of current_id to the parent element. */
467 protected Element addSiblings(Element parent, String parent_id, String current_id) {
468 Element current_node = (Element)parent.getFirstChild();
469 if (current_node ==null) {
470 // create a sensible error message
471 System.err.println("GS2Retrieve Error: there should be a first child.");
472 return null;
473 }
474 // remove the current child,- will add it in later in its correct place
475 parent.removeChild(current_node);
476
477 // add in all the siblings,
478 addDescendants(parent, parent_id, false);
479
480 // find the node that is now the current node
481 // this assumes that the new node that was created is the same as
482 // the old one that was removed - we may want to replace the new one
483 // with the old one.
484 Element new_current = GSXML.getNamedElement(parent, current_node.getNodeName(), GSXML.NODE_ID_ATT, current_id);
485 return new_current;
486
487 }
488 /** Returns true if the OID specifies a leaf node, false otherwise
489 Note: this makes a request to the GDBM database so it may not be
490 a particularly cheap operation */
491 protected boolean isLeafNode(String oid)
492 {
493 DBInfo info = this.gdbm_src.getInfo(oid);
494 String children = info.getInfo("contains");
495 return (children.equals(""));
496 }
497
498 // for now just use CL for classifiers - should have a type? in teh gdbm
499 // database.
500 protected boolean isClassifier(String oid) {
501 if (oid.startsWith("CL")) {
502 return true;
503 }
504 return false;
505 }
506
507 protected Element processDocumentStructureRetrieve(Element request) {
508 return genericStructureRetrieve(request, DOCUMENT);
509 }
510
511 protected Element processClassifierBrowse(Element request) {
512 return genericStructureRetrieve(request, CLASSIFIER);
513 }
514
515 /** Retrieve the structure of a document */
516 protected Element genericStructureRetrieve(Element request, int type)
517 {
518 // Create a new (empty) result message
519 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
520
521 String node_name;
522 String service_name;
523 if (type==DOCUMENT) {
524 service_name = DOCUMENT_STRUCTURE_RETRIEVE_SERVICE;
525 node_name = GSXML.DOC_NODE_ELEM;
526 } else {
527 service_name = CLASSIFIER_SERVICE;
528 node_name = GSXML.CLASS_NODE_ELEM;
529 }
530
531 result.setAttribute(GSXML.FROM_ATT, service_name);
532 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
533
534 String lang = request.getAttribute(GSXML.LANG_ATT);
535 Element query_doc_list = (Element) GSXML.getChildByTagName(request, node_name+GSXML.LIST_MODIFIER);
536 if (query_doc_list == null) {
537 System.err.println("GS2Retrieve Error: DocumentStructureRetrieve request specified no doc nodes.\n");
538 return result;
539 }
540
541 // Get the parameters of the request
542 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
543 if (param_list == null) {
544 System.err.println("GS2Retrieve Error: DocumentStructureRetrieve request had no paramList.");
545 return result; // Return the empty result
546 }
547
548 // the type of info required
549 boolean want_structure = false;
550 boolean want_info = false;
551
552 Vector info_types=new Vector();
553 // The document structure information desired
554 boolean want_ancestors = false;
555 boolean want_parent = false;
556 boolean want_siblings = false;
557 boolean want_children = false;
558 boolean want_descendants = false;
559
560 boolean want_entire_structure = false;
561 // Process the request parameters
562 NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
563 for (int i=0; i<params.getLength();i++) {
564
565 Element param = (Element)params.item(i);
566 String p_name = param.getAttribute(GSXML.NAME_ATT);
567 String p_value = GSXML.getValue(param);
568 // Identify the structure information desired
569 if (p_name.equals(STRUCT_PARAM)) {
570 want_structure = true;
571
572 // This is NOT locale sensitive
573 if (p_value.equals(STRUCT_ANCESTORS))
574 want_ancestors = true;
575 else if (p_value.equals(STRUCT_PARENT))
576 want_parent = true;
577 else if (p_value.equals(STRUCT_SIBS))
578 want_siblings = true;
579 else if (p_value.equals(STRUCT_CHILDREN))
580 want_children = true;
581 else if (p_value.equals(STRUCT_DESCENDS))
582 want_descendants = true;
583 else if (p_value.equals(STRUCT_ENTIRE))
584 want_entire_structure = true;
585 else
586 System.err.println("GS2Retrieve Warning: Unknown value \"" + p_value + "\".");
587 } else if (p_name.equals(INFO_PARAM)) {
588 want_info = true;
589 info_types.add(p_value);
590 }
591 }
592
593 // Make sure there is no repeated information
594 if (want_ancestors)
595 want_parent = false;
596 if (want_descendants)
597 want_children = false;
598
599
600
601 Element doc_list = this.doc.createElement(node_name+GSXML.LIST_MODIFIER);
602 result.appendChild(doc_list);
603
604 // Get the documents
605 String[] doc_ids = GSXML.getAttributeValuesFromList(query_doc_list,
606 GSXML.NODE_ID_ATT);
607 for (int i = 0; i < doc_ids.length; i++) {
608 String doc_id = doc_ids[i];
609
610 if (OID.needsTranslating(doc_id)) {
611 doc_id = this.gdbm_src.translateOID(doc_id);
612 }
613
614 // Add the document to the list
615 Element doc = this.doc.createElement(node_name);
616 doc_list.appendChild(doc);
617 doc.setAttribute(GSXML.NODE_ID_ATT, doc_id);
618
619
620 if (want_info) {
621
622 Element info_elem = this.doc.createElement("nodeStructureInfo");
623 doc.appendChild(info_elem);
624
625 for (int j=0; j<info_types.size(); j++) {
626 String info_type = (String)info_types.get(j);
627 Element inf = getInfo(doc_id, info_type);
628 if (inf != null) {
629 info_elem.appendChild(inf);
630 }
631 }
632 }
633 if (want_structure) {
634 // all structure info goes into a nodeStructure elem
635 Element structure_elem = this.doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
636 doc.appendChild(structure_elem);
637
638 if (want_entire_structure) {
639 String top_id = OID.getTop(doc_id);
640 Element top_node = createDocNode(top_id, true, false);
641 addDescendants(top_node, top_id, true);
642 structure_elem.appendChild(top_node);
643 continue; // with the next document, we dont need to do any more here
644 }
645
646 // Add the requested structure information
647 Element current = createDocNode(doc_id, false, false);
648
649 //Ancestors: continually add parent nodes until the root is reached
650 Element top_node = current; // the top node so far
651 if (want_ancestors) {
652 String current_id = doc_id;
653 while (true) {
654 Element parent = getParent(current_id);
655 if (parent == null)
656 break;
657
658 parent.appendChild(top_node);
659 current_id = parent.getAttribute(GSXML.NODE_ID_ATT);
660 top_node = parent;
661 }
662 }
663 // Parent: get the parent of the selected node
664 if (want_parent) {
665 Element parent = getParent(doc_id);
666 if (parent != null) {
667 parent.appendChild(current);
668 top_node = parent;
669 }
670 }
671
672
673 // now the top node is the root of the structure
674 structure_elem.appendChild(top_node);
675
676 //Siblings: get the other descendants of the selected node's parent
677 if (want_siblings) {
678 Element parent = (Element)current.getParentNode(); // this may be the structure element if there has been no request for parents or ancestors
679 String parent_id = OID.getParent(doc_id);
680
681 // add siblings, - returns a pointer to the new current node
682 current = addSiblings(parent, parent_id, doc_id);
683 }
684
685 // Children: get the descendants, but only one level deep
686 if (want_children)
687 addDescendants(current, doc_id, false);
688 // Descendants: recursively get every descendant of the selected node
689 if (want_descendants)
690 addDescendants(current, doc_id, true);
691 } // if want structure
692 } // for each doc
693 return result;
694 }
695
696
697 protected Element processDocumentMetadataRetrieve(Element request) {
698 return genericMetadataRetrieve(request, DOCUMENT);
699 }
700
701 protected Element processClassifierBrowseMetadataRetrieve(Element request) {
702 return genericMetadataRetrieve(request, CLASSIFIER);
703 }
704
705
706 /** Retrieve metadata associated with a document or classifier node*/
707 protected Element genericMetadataRetrieve(Element request, int type)
708 {
709 // Create a new (empty) result message
710 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
711
712 String node_name;
713 String lang = request.getAttribute(GSXML.LANG_ATT);
714 String service_name;
715 if (type==DOCUMENT) {
716 service_name = DOCUMENT_METADATA_RETRIEVE_SERVICE;
717 node_name = GSXML.DOC_NODE_ELEM;
718 } else {
719 service_name = CLASSIFIER_METADATA_SERVICE;
720 node_name = GSXML.CLASS_NODE_ELEM;
721 }
722 result.setAttribute(GSXML.FROM_ATT, service_name);
723 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
724
725 // Get the parameters of the request
726 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
727 if (param_list == null) {
728 System.err.println("GS2Retrieve, DocumentMetadataRetrieve Error: missing paramList.\n");
729 return result; // Return the empty result
730 }
731
732 boolean extlink = false;
733 // The metadata information required
734 Vector metadata_list = new Vector();
735 boolean all_metadata = false;
736 // Process the request parameters
737 Element param = (Element) param_list.getFirstChild();
738 while (param != null) {
739 // Identify the metadata information desired
740 if (param.getAttribute(GSXML.NAME_ATT).equals("metadata")) {
741 String metadata = GSXML.getValue(param);
742 if (metadata.equals("all")) {
743 all_metadata = true;
744 break;
745 }
746 metadata_list.add(metadata);
747 } else if (param.getAttribute(GSXML.NAME_ATT).equals(EXTLINK_PARAM)&& GSXML.getValue(param).equals("1")) {
748 extlink = true;
749 }
750 param = (Element) param.getNextSibling();
751 }
752
753 Element node_list = this.doc.createElement(node_name+GSXML.LIST_MODIFIER);
754 result.appendChild(node_list);
755
756 // Get the documents
757 Element request_node_list = (Element) GSXML.getChildByTagName(request, node_name+GSXML.LIST_MODIFIER);
758 if (request_node_list == null) {
759 System.err.println("Error: DocumentMetadataRetrieve request had no "+node_name+"List.\n");
760 return result;
761 }
762
763 NodeList request_nodes = request_node_list.getChildNodes();
764 for (int i = 0; i < request_nodes.getLength(); i++) {
765 Element request_node = (Element) request_nodes.item(i);
766 String node_id = request_node.getAttribute(GSXML.NODE_ID_ATT);
767
768 if (extlink) {
769 if (OID.needsTranslating(node_id)) {
770 // just ignore the extension cos it has no meaning here
771 // or should it be added back on for the next step???
772 node_id = this.gdbm_src.extlink2OID(node_id.substring(0,node_id.length()-3));
773 } else {
774 node_id = this.gdbm_src.extlink2OID(node_id);
775 }
776 }
777 else if (OID.needsTranslating(node_id)) {
778 node_id = this.gdbm_src.translateOID(node_id);
779 }
780
781 // Add the document to the list
782 Element new_node = (Element)this.doc.importNode(request_node, false);
783 node_list.appendChild(new_node);
784
785 // Add the requested metadata information
786 Element node_meta_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
787 new_node.appendChild(node_meta_list);
788 DBInfo info = this.gdbm_src.getInfo(node_id);
789 if (info == null) {// I have had a case where it is null!
790 continue;
791 }
792 if (all_metadata) {
793 // return everything out of the database
794 Set keys = info.getKeys();
795 Iterator it = keys.iterator();
796 while(it.hasNext()) {
797 String key = (String)it.next();
798 String value = info.getInfo(key);
799 GSXML.addMetadata(this.doc, node_meta_list, key, this.macro_resolver.resolve(value, lang, GS2MacroResolver.SCOPE_META, node_id, info));
800 }
801 } else { // just get the selected ones
802
803 for (int m = 0; m < metadata_list.size(); m++) {
804 String metadata = (String) metadata_list.get(m);
805 String value = getMetadata(node_id, info, metadata, lang);
806 if (!value.equals("")) {
807 GSXML.addMetadata(this.doc, node_meta_list, metadata, value);
808 }
809 }
810 }
811 }
812
813 return result;
814 }
815
816 protected String getMetadata(String node_id, DBInfo info,
817 String metadata, String lang) {
818 boolean multiple = false;
819 String relation = "";
820 String separator = ", ";
821 int pos = metadata.indexOf(GSConstants.META_RELATION_SEP);
822 if (pos ==-1) {
823 // just a plain meta entry eg dc.Title
824 return macro_resolver.resolve((String)info.getInfo(metadata), lang, GS2MacroResolver.SCOPE_META, node_id, info);
825 }
826
827 String temp = metadata.substring(0, pos);
828 metadata = metadata.substring(pos+1);
829 // check for all on the front
830 if (temp.equals("all")) {
831 multiple=true;
832 pos = metadata.indexOf(GSConstants.META_RELATION_SEP);
833 if (pos ==-1) {
834 temp = "";
835 } else {
836 temp = metadata.substring(0, pos);
837 metadata = metadata.substring(pos+1);
838 }
839 }
840
841 // now check for relational info
842 if (temp.equals("parent") || temp.equals("root") || temp.equals( "ancestors")) { // "current" "siblings" "children" "descendents"
843 relation = temp;
844 pos = metadata.indexOf(GSConstants.META_RELATION_SEP);
845 if (pos == -1) {
846 temp = "";
847 } else {
848 temp = metadata.substring(0, pos);
849 metadata = metadata.substring(pos+1);
850 }
851 }
852
853 // now look for separator info
854 if (temp.startsWith(GSConstants.META_SEPARATOR_SEP) && temp.endsWith(GSConstants.META_SEPARATOR_SEP)) {
855 separator = temp.substring(1, temp.length()-1);
856
857 }
858
859 String relation_id = node_id;
860 if (relation.equals("parent") || relation.equals("ancestors")) {
861 relation_id = OID.getParent(node_id);
862 // parent or ancestor does not include self
863 if (relation_id.equals(node_id)){
864 return "";
865 }
866 } else if (relation.equals("root")) {
867 relation_id = OID.getTop(node_id);
868 }
869
870 // now we either have a single node, or we have ancestors
871 DBInfo relation_info;
872 if (relation_id.equals(node_id)) {
873 relation_info = info;
874 } else {
875 relation_info = this.gdbm_src.getInfo(relation_id);
876 }
877 if (relation_info == null) {
878 return "";
879 }
880
881 StringBuffer result = new StringBuffer();
882
883 if (!multiple) {
884 result.append(this.macro_resolver.resolve(relation_info.getInfo(metadata), lang, GS2MacroResolver.SCOPE_META, relation_id, relation_info));
885 } else {
886 // we have multiple meta
887 Vector values = relation_info.getMultiInfo(metadata);
888 if (values != null) {
889 boolean first = true;
890 for (int i=0; i<values.size(); i++) {
891 if (first) {
892 first = false;
893 } else {
894 result.append(separator);
895 }
896 result.append(this.macro_resolver.resolve((String)values.elementAt(i), lang, GS2MacroResolver.SCOPE_META, relation_id, relation_info));
897 }
898 }
899 }
900 // if not ancestors, then this is all we do
901 if (!relation.equals("ancestors")) {
902 return result.toString();
903 }
904
905 // now do the ancestors
906 String current_id = relation_id;
907 relation_id = OID.getParent(current_id);
908 while (!relation_id.equals(current_id)) {
909 relation_info = this.gdbm_src.getInfo(relation_id);
910 if (relation_info == null) return result.toString();
911 if (!multiple) {
912 result.insert(0, separator);
913 result.insert(0, this.macro_resolver.resolve(relation_info.getInfo(metadata), lang, GS2MacroResolver.SCOPE_META, relation_id, relation_info));
914 } else {
915 Vector values = relation_info.getMultiInfo(metadata);
916 if (values != null) {
917 for (int i=values.size()-1; i>=0; i--) {
918 result.insert(0, separator);
919 result.insert(0, this.macro_resolver.resolve((String)values.elementAt(i), lang, GS2MacroResolver.SCOPE_META, relation_id, relation_info));
920 }
921 }
922
923 }
924 current_id = relation_id;
925 relation_id = OID.getParent(current_id);
926 }
927 return result.toString();
928 }
929
930 /** Retrieve the content of a document - implemented by concrete subclasses */
931 protected abstract Element processDocumentContentRetrieve(Element request);
932
933 /** needs to get info from gdbm database - if the calling code gets it already it may pay to pass it in instead */
934 protected String resolveTextMacros(String doc_content, String doc_id, String lang)
935 {
936 String top_doc_id = OID.getTop(doc_id);
937 DBInfo info = this.gdbm_src.getInfo(top_doc_id);
938 String archivedir = info.getInfo("archivedir");
939 String image_dir = this.site_http_address + "/collect/"+this.cluster_name+"/index/assoc/"+archivedir;
940
941 // Resolve all "_httpdocimg_"s
942 doc_content = doc_content.replaceAll("_httpdocimg_", image_dir);
943 // resolve any collection specific macros
944 doc_content = macro_resolver.resolve(doc_content, lang, GS2MacroResolver.SCOPE_TEXT, top_doc_id, info);
945 return doc_content;
946 }
947
948 protected Element getInfo(String doc_id, String info_type) {
949
950 String value="";
951 if (info_type.equals(INFO_NUM_SIBS)) {
952 String parent_id = OID.getParent(doc_id);
953 if (parent_id.equals(doc_id)) {
954 value="0";
955 } else {
956 value = String.valueOf(getNumChildren(parent_id));
957 }
958 } else if (info_type.equals(INFO_NUM_CHILDREN)) {
959 value = String.valueOf(getNumChildren(doc_id));
960 } else if (info_type.equals(INFO_SIB_POS)) {
961 String parent_id = OID.getParent(doc_id);
962 if (parent_id.equals(doc_id)) {
963 value="-1";
964 } else {
965 DBInfo info = this.gdbm_src.getInfo(parent_id);
966 String contains = info.getInfo("contains");
967 contains = contains.replaceAll("\"", parent_id);
968 String [] children = contains.split(";");
969 for (int i=0;i<children.length;i++) {
970 String child_id = children[i];
971 if (child_id.equals(doc_id)) {
972 value = String.valueOf(i+1); // make it from 1 to length
973 break;
974 }
975 }
976 }
977 } else {
978 return null;
979 }
980 Element info_elem = this.doc.createElement("info");
981 info_elem.setAttribute(GSXML.NAME_ATT, info_type);
982 info_elem.setAttribute(GSXML.VALUE_ATT, value);
983 return info_elem;
984 }
985
986 protected int getNumChildren(String doc_id) {
987 DBInfo info = this.gdbm_src.getInfo(doc_id);
988 String contains = info.getInfo("contains");
989 if (contains.equals("")) {
990 return 0;
991 }
992 String [] children = contains.split(";");
993 return children.length;
994 }
995
996}
Note: See TracBrowser for help on using the repository browser.