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

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

several changes all at once. GDBMWrapper methods docnum2Oid and oid2Docnum renamed, the content and metadata retrieve methods now look for an extra parameter: ext. this is for doing greenstone 2 relative external links. where you get a url, and you look this up in the database to turn it into a greensotne hash id.

  • Property svn:keywords set to Author Date Id Revision
File size: 34.5 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: 8674 $
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 teh 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 teh doc type att
406 if (is_top && is_leaf) { // a single section document
407 node.setAttribute(GSXML.DOC_TYPE_ATT, "simple");
408
409 } else {
410
411 if (!is_top) { // we need to look at the top info
412 info = this.gdbm_src.getInfo(top_id);
413 }
414
415 String childtype = info.getInfo("childtype");
416 if (childtype.equals("Paged")) {
417 node.setAttribute(GSXML.DOC_TYPE_ATT, "paged");
418 } else {
419 node.setAttribute(GSXML.DOC_TYPE_ATT, "hierarchy");
420 }
421 }
422
423 }
424 node.setAttribute(GSXML.NODE_ID_ATT, node_id);
425 return node;
426
427 }
428 /** Returns the parent of a specified documentID, or null if none exists */
429 protected Element getParent(String doc_id)
430 {
431 String parent_id = OID.getParent(doc_id);
432 if (parent_id.equals(doc_id))
433 return null;
434
435 return createDocNode(parent_id, true, false);
436 }
437
438
439 /** adds all the children of doc_id the the doc element,
440 * and if recursive=true, adds all their children as well*/
441 protected void addDescendants(Element doc, String doc_id,
442 boolean recursive)
443 {
444 DBInfo info = this.gdbm_src.getInfo(doc_id);
445 String contains = info.getInfo("contains");
446
447 StringTokenizer st = new StringTokenizer(contains, ";");
448 while (st.hasMoreTokens()) {
449 String child_id = st.nextToken().replaceAll("\"", doc_id);
450 Element child = createDocNode(child_id, false, true);
451 doc.appendChild(child);
452
453 // Apply recursively, if desired
454 if (recursive) {
455 addDescendants(child, child_id, recursive);
456 }
457
458 }
459 }
460
461 /** adds all the siblings of current_id to the parent element. */
462 protected Element addSiblings(Element parent, String parent_id, String current_id) {
463 Element current_node = (Element)parent.getFirstChild();
464 if (current_node ==null) {
465 // create a sensible error message
466 System.err.println("GS2Retrieve Error: there should be a first child.");
467 return null;
468 }
469 // remove the current child,- will add it in later in its correct place
470 parent.removeChild(current_node);
471
472 // add in all the siblings,
473 addDescendants(parent, parent_id, false);
474
475 // find the node that is now the current node
476 // this assumes that the new node that was created is the same as
477 // the old one that was removed - we may want to replace the new one
478 // with the old one.
479 Element new_current = GSXML.getNamedElement(parent, current_node.getNodeName(), GSXML.NODE_ID_ATT, current_id);
480 return new_current;
481
482 }
483 /** Returns true if the OID specifies a leaf node, false otherwise
484 Note: this makes a request to the GDBM database so it may not be
485 a particularly cheap operation */
486 protected boolean isLeafNode(String oid)
487 {
488 DBInfo info = this.gdbm_src.getInfo(oid);
489 String children = info.getInfo("contains");
490 return (children.equals(""));
491 }
492
493 // for now just use CL for classifiers - should have a type? in teh gdbm
494 // database.
495 protected boolean isClassifier(String oid) {
496 if (oid.startsWith("CL")) {
497 return true;
498 }
499 return false;
500 }
501
502 protected Element processDocumentStructureRetrieve(Element request) {
503 return genericStructureRetrieve(request, DOCUMENT);
504 }
505
506 protected Element processClassifierBrowse(Element request) {
507 return genericStructureRetrieve(request, CLASSIFIER);
508 }
509
510 /** Retrieve the structure of a document */
511 protected Element genericStructureRetrieve(Element request, int type)
512 {
513 // Create a new (empty) result message
514 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
515
516 String node_name;
517 String service_name;
518 if (type==DOCUMENT) {
519 service_name = DOCUMENT_STRUCTURE_RETRIEVE_SERVICE;
520 node_name = GSXML.DOC_NODE_ELEM;
521 } else {
522 service_name = CLASSIFIER_SERVICE;
523 node_name = GSXML.CLASS_NODE_ELEM;
524 }
525
526 result.setAttribute(GSXML.FROM_ATT, service_name);
527 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
528
529 String lang = request.getAttribute(GSXML.LANG_ATT);
530 Element query_doc_list = (Element) GSXML.getChildByTagName(request, node_name+GSXML.LIST_MODIFIER);
531 if (query_doc_list == null) {
532 System.err.println("GS2Retrieve Error: DocumentStructureRetrieve request specified no doc nodes.\n");
533 return result;
534 }
535
536 // Get the parameters of the request
537 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
538 if (param_list == null) {
539 System.err.println("GS2Retrieve Error: DocumentStructureRetrieve request had no paramList.");
540 return result; // Return the empty result
541 }
542
543 // the type of info required
544 boolean want_structure = false;
545 boolean want_info = false;
546
547 Vector info_types=new Vector();
548 // The document structure information desired
549 boolean want_ancestors = false;
550 boolean want_parent = false;
551 boolean want_siblings = false;
552 boolean want_children = false;
553 boolean want_descendants = false;
554
555 boolean want_entire_structure = false;
556 // Process the request parameters
557 NodeList params = param_list.getElementsByTagName(GSXML.PARAM_ELEM);
558 for (int i=0; i<params.getLength();i++) {
559
560 Element param = (Element)params.item(i);
561 String p_name = param.getAttribute(GSXML.NAME_ATT);
562 String p_value = GSXML.getValue(param);
563 // Identify the structure information desired
564 if (p_name.equals(STRUCT_PARAM)) {
565 want_structure = true;
566
567 // This is NOT locale sensitive
568 if (p_value.equals(STRUCT_ANCESTORS))
569 want_ancestors = true;
570 else if (p_value.equals(STRUCT_PARENT))
571 want_parent = true;
572 else if (p_value.equals(STRUCT_SIBS))
573 want_siblings = true;
574 else if (p_value.equals(STRUCT_CHILDREN))
575 want_children = true;
576 else if (p_value.equals(STRUCT_DESCENDS))
577 want_descendants = true;
578 else if (p_value.equals(STRUCT_ENTIRE))
579 want_entire_structure = true;
580 else
581 System.err.println("GS2Retrieve Warning: Unknown value \"" + p_value + "\".");
582 } else if (p_name.equals(INFO_PARAM)) {
583 want_info = true;
584 info_types.add(p_value);
585 }
586 }
587
588 // Make sure there is no repeated information
589 if (want_ancestors)
590 want_parent = false;
591 if (want_descendants)
592 want_children = false;
593
594
595
596 Element doc_list = this.doc.createElement(node_name+GSXML.LIST_MODIFIER);
597 result.appendChild(doc_list);
598
599 // Get the documents
600 String[] doc_ids = GSXML.getAttributeValuesFromList(query_doc_list,
601 GSXML.NODE_ID_ATT);
602 for (int i = 0; i < doc_ids.length; i++) {
603 String doc_id = doc_ids[i];
604
605 if (OID.needsTranslating(doc_id)) {
606 doc_id = this.gdbm_src.translateOID(doc_id);
607 }
608
609 // Add the document to the list
610 Element doc = this.doc.createElement(node_name);
611 doc_list.appendChild(doc);
612 doc.setAttribute(GSXML.NODE_ID_ATT, doc_id);
613
614
615 if (want_info) {
616
617 Element info_elem = this.doc.createElement("nodeStructureInfo");
618 doc.appendChild(info_elem);
619
620 for (int j=0; j<info_types.size(); j++) {
621 String info_type = (String)info_types.get(j);
622 Element inf = getInfo(doc_id, info_type);
623 if (inf != null) {
624 info_elem.appendChild(inf);
625 }
626 }
627 }
628 if (want_structure) {
629 // all structure info goes into a nodeStructure elem
630 Element structure_elem = this.doc.createElement(GSXML.NODE_STRUCTURE_ELEM);
631 doc.appendChild(structure_elem);
632
633 if (want_entire_structure) {
634 String top_id = OID.getTop(doc_id);
635 Element top_node = createDocNode(top_id, true, false);
636 addDescendants(top_node, top_id, true);
637 structure_elem.appendChild(top_node);
638 continue; // with the next document, we dont need to do any more here
639 }
640
641 // Add the requested structure information
642 Element current = createDocNode(doc_id, false, false);
643
644 //Ancestors: continually add parent nodes until the root is reached
645 Element top_node = current; // the top node so far
646 if (want_ancestors) {
647 String current_id = doc_id;
648 while (true) {
649 Element parent = getParent(current_id);
650 if (parent == null)
651 break;
652
653 parent.appendChild(top_node);
654 current_id = parent.getAttribute(GSXML.NODE_ID_ATT);
655 top_node = parent;
656 }
657 }
658 // Parent: get the parent of the selected node
659 if (want_parent) {
660 Element parent = getParent(doc_id);
661 if (parent != null) {
662 parent.appendChild(current);
663 top_node = parent;
664 }
665 }
666
667
668 // now the top node is the root of the structure
669 structure_elem.appendChild(top_node);
670
671 //Siblings: get the other descendants of the selected node's parent
672 if (want_siblings) {
673 Element parent = (Element)current.getParentNode(); // this may be the structure element if there has been no request for parents or ancestors
674 String parent_id = OID.getParent(doc_id);
675
676 // add siblings, - returns a pointer to the new current node
677 current = addSiblings(parent, parent_id, doc_id);
678 }
679
680 // Children: get the descendants, but only one level deep
681 if (want_children)
682 addDescendants(current, doc_id, false);
683 // Descendants: recursively get every descendant of the selected node
684 if (want_descendants)
685 addDescendants(current, doc_id, true);
686 } // if want structure
687 } // for each doc
688 return result;
689 }
690
691
692 protected Element processDocumentMetadataRetrieve(Element request) {
693 return genericMetadataRetrieve(request, DOCUMENT);
694 }
695
696 protected Element processClassifierBrowseMetadataRetrieve(Element request) {
697 return genericMetadataRetrieve(request, CLASSIFIER);
698 }
699
700
701 /** Retrieve metadata associated with a document or classifier node*/
702 protected Element genericMetadataRetrieve(Element request, int type)
703 {
704 // Create a new (empty) result message
705 Element result = this.doc.createElement(GSXML.RESPONSE_ELEM);
706
707 String node_name;
708 String lang = request.getAttribute(GSXML.LANG_ATT);
709 String service_name;
710 if (type==DOCUMENT) {
711 service_name = DOCUMENT_METADATA_RETRIEVE_SERVICE;
712 node_name = GSXML.DOC_NODE_ELEM;
713 } else {
714 service_name = CLASSIFIER_METADATA_SERVICE;
715 node_name = GSXML.CLASS_NODE_ELEM;
716 }
717 result.setAttribute(GSXML.FROM_ATT, service_name);
718 result.setAttribute(GSXML.TYPE_ATT, GSXML.REQUEST_TYPE_PROCESS);
719
720 // Get the parameters of the request
721 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM+GSXML.LIST_MODIFIER);
722 if (param_list == null) {
723 System.err.println("GS2Retrieve, DocumentMetadataRetrieve Error: missing paramList.\n");
724 return result; // Return the empty result
725 }
726
727 boolean extlink = false;
728 // The metadata information required
729 Vector metadata_list = new Vector();
730 boolean all_metadata = false;
731 // Process the request parameters
732 Element param = (Element) param_list.getFirstChild();
733 while (param != null) {
734 // Identify the metadata information desired
735 if (param.getAttribute(GSXML.NAME_ATT).equals("metadata")) {
736 String metadata = GSXML.getValue(param);
737 if (metadata.equals("all")) {
738 all_metadata = true;
739 break;
740 }
741 metadata_list.add(metadata);
742 } else if (param.getAttribute(GSXML.NAME_ATT).equals(EXTLINK_PARAM)&& GSXML.getValue(param).equals("1")) {
743 extlink = true;
744 }
745 param = (Element) param.getNextSibling();
746 }
747
748 Element node_list = this.doc.createElement(node_name+GSXML.LIST_MODIFIER);
749 result.appendChild(node_list);
750
751 // Get the documents
752 Element request_node_list = (Element) GSXML.getChildByTagName(request, node_name+GSXML.LIST_MODIFIER);
753 if (request_node_list == null) {
754 System.err.println("Error: DocumentMetadataRetrieve request had no "+node_name+"List.\n");
755 return result;
756 }
757
758 NodeList request_nodes = request_node_list.getChildNodes();
759 for (int i = 0; i < request_nodes.getLength(); i++) {
760 Element request_node = (Element) request_nodes.item(i);
761 String node_id = request_node.getAttribute(GSXML.NODE_ID_ATT);
762
763 if (extlink) {
764 if (OID.needsTranslating(node_id)) {
765 // just ignore the extension cos it has no meaning here
766 // or should it be added back on for the next step???
767 node_id = this.gdbm_src.extlink2OID(node_id.substring(0,node_id.length()-3));
768 } else {
769 node_id = this.gdbm_src.extlink2OID(node_id);
770 }
771 }
772 else if (OID.needsTranslating(node_id)) {
773 node_id = this.gdbm_src.translateOID(node_id);
774 }
775
776 // Add the document to the list
777 Element new_node = (Element)this.doc.importNode(request_node, false);
778 node_list.appendChild(new_node);
779
780 // Add the requested metadata information
781 Element node_meta_list = this.doc.createElement(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
782 new_node.appendChild(node_meta_list);
783 DBInfo info = this.gdbm_src.getInfo(node_id);
784 if (info == null) {// I have had a case where it is null!
785 continue;
786 }
787 if (all_metadata) {
788 // return everything out of the database
789 Set keys = info.getKeys();
790 Iterator it = keys.iterator();
791 while(it.hasNext()) {
792 String key = (String)it.next();
793 String value = info.getInfo(key);
794 GSXML.addMetadata(this.doc, node_meta_list, key, this.macro_resolver.resolve(value, lang, GS2MacroResolver.SCOPE_META, node_id, info));
795 }
796 } else { // just get the selected ones
797
798 for (int m = 0; m < metadata_list.size(); m++) {
799 String metadata = (String) metadata_list.get(m);
800 String value = getMetadata(node_id, info, metadata, lang);
801 if (!value.equals("")) {
802 GSXML.addMetadata(this.doc, node_meta_list, metadata, value);
803 }
804 }
805 }
806 }
807
808 return result;
809 }
810
811 protected String getMetadata(String node_id, DBInfo info,
812 String metadata, String lang) {
813 boolean multiple = false;
814 String relation = "";
815 String separator = ", ";
816 int pos = metadata.indexOf(GSConstants.META_RELATION_SEP);
817 if (pos ==-1) {
818 // just a plain meta entry eg dc.Title
819 return macro_resolver.resolve((String)info.getInfo(metadata), lang, GS2MacroResolver.SCOPE_META, node_id, info);
820 }
821
822 String temp = metadata.substring(0, pos);
823 metadata = metadata.substring(pos+1);
824 // check for all on the front
825 if (temp.equals("all")) {
826 multiple=true;
827 pos = metadata.indexOf(GSConstants.META_RELATION_SEP);
828 if (pos ==-1) {
829 temp = "";
830 } else {
831 temp = metadata.substring(0, pos);
832 metadata = metadata.substring(pos+1);
833 }
834 }
835
836 // now check for relational info
837 if (temp.equals("parent") || temp.equals("root") || temp.equals( "ancestors")) { // "current" "siblings" "children" "descendents"
838 relation = temp;
839 pos = metadata.indexOf(GSConstants.META_RELATION_SEP);
840 if (pos == -1) {
841 temp = "";
842 } else {
843 temp = metadata.substring(0, pos);
844 metadata = metadata.substring(pos+1);
845 }
846 }
847
848 // now look for separator info
849 if (temp.startsWith(GSConstants.META_SEPARATOR_SEP) && temp.endsWith(GSConstants.META_SEPARATOR_SEP)) {
850 separator = temp.substring(1, temp.length()-1);
851
852 }
853
854 String relation_id = node_id;
855 if (relation.equals("parent") || relation.equals("ancestors")) {
856 relation_id = OID.getParent(node_id);
857 // parent or ancestor does not include self
858 if (relation_id.equals(node_id)){
859 return "";
860 }
861 } else if (relation.equals("root")) {
862 relation_id = OID.getTop(node_id);
863 }
864
865 // now we either have a single node, or we have ancestors
866 DBInfo relation_info;
867 if (relation_id.equals(node_id)) {
868 relation_info = info;
869 } else {
870 relation_info = this.gdbm_src.getInfo(relation_id);
871 }
872 if (relation_info == null) {
873 return "";
874 }
875
876 StringBuffer result = new StringBuffer();
877
878 if (!multiple) {
879 result.append(this.macro_resolver.resolve(relation_info.getInfo(metadata), lang, GS2MacroResolver.SCOPE_META, relation_id, relation_info));
880 } else {
881 // we have multiple meta
882 Vector values = relation_info.getMultiInfo(metadata);
883 if (values != null) {
884 boolean first = true;
885 for (int i=0; i<values.size(); i++) {
886 if (first) {
887 first = false;
888 } else {
889 result.append(separator);
890 }
891 result.append(this.macro_resolver.resolve((String)values.elementAt(i), lang, GS2MacroResolver.SCOPE_META, relation_id, relation_info));
892 }
893 }
894 }
895 // if not ancestors, then this is all we do
896 if (!relation.equals("ancestors")) {
897 return result.toString();
898 }
899
900 // now do the ancestors
901 String current_id = relation_id;
902 relation_id = OID.getParent(current_id);
903 while (!relation_id.equals(current_id)) {
904 relation_info = this.gdbm_src.getInfo(relation_id);
905 if (relation_info == null) return result.toString();
906 if (!multiple) {
907 result.insert(0, separator);
908 result.insert(0, this.macro_resolver.resolve(relation_info.getInfo(metadata), lang, GS2MacroResolver.SCOPE_META, relation_id, relation_info));
909 } else {
910 Vector values = relation_info.getMultiInfo(metadata);
911 if (values != null) {
912 for (int i=values.size()-1; i>=0; i--) {
913 result.insert(0, separator);
914 result.insert(0, this.macro_resolver.resolve((String)values.elementAt(i), lang, GS2MacroResolver.SCOPE_META, relation_id, relation_info));
915 }
916 }
917
918 }
919 current_id = relation_id;
920 relation_id = OID.getParent(current_id);
921 }
922 return result.toString();
923 }
924
925 /** Retrieve the content of a document - implemented by concrete subclasses */
926 protected abstract Element processDocumentContentRetrieve(Element request);
927
928 /** needs to get info from gdbm database - if the calling code gets it already it may pay to pass it in instead */
929 protected String resolveTextMacros(String doc_content, String doc_id, String lang)
930 {
931 String top_doc_id = OID.getTop(doc_id);
932 DBInfo info = this.gdbm_src.getInfo(top_doc_id);
933 String archivedir = info.getInfo("archivedir");
934 String image_dir = this.site_http_address + "/collect/"+this.cluster_name+"/index/assoc/"+archivedir;
935
936 // Resolve all "_httpdocimg_"s
937 doc_content = doc_content.replaceAll("_httpdocimg_", image_dir);
938 // resolve any collection specific macros
939 doc_content = macro_resolver.resolve(doc_content, lang, GS2MacroResolver.SCOPE_TEXT, top_doc_id, info);
940 return doc_content;
941 }
942
943 protected Element getInfo(String doc_id, String info_type) {
944
945 String value="";
946 if (info_type.equals(INFO_NUM_SIBS)) {
947 String parent_id = OID.getParent(doc_id);
948 if (parent_id.equals(doc_id)) {
949 value="0";
950 } else {
951 value = String.valueOf(getNumChildren(parent_id));
952 }
953 } else if (info_type.equals(INFO_NUM_CHILDREN)) {
954 value = String.valueOf(getNumChildren(doc_id));
955 } else if (info_type.equals(INFO_SIB_POS)) {
956 String parent_id = OID.getParent(doc_id);
957 if (parent_id.equals(doc_id)) {
958 value="-1";
959 } else {
960 DBInfo info = this.gdbm_src.getInfo(parent_id);
961 String contains = info.getInfo("contains");
962 contains = contains.replaceAll("\"", parent_id);
963 String [] children = contains.split(";");
964 for (int i=0;i<children.length;i++) {
965 String child_id = children[i];
966 if (child_id.equals(doc_id)) {
967 value = String.valueOf(i+1); // make it from 1 to length
968 break;
969 }
970 }
971 }
972 } else {
973 return null;
974 }
975 Element info_elem = this.doc.createElement("info");
976 info_elem.setAttribute(GSXML.NAME_ATT, info_type);
977 info_elem.setAttribute(GSXML.VALUE_ATT, value);
978 return info_elem;
979 }
980
981 protected int getNumChildren(String doc_id) {
982 DBInfo info = this.gdbm_src.getInfo(doc_id);
983 String contains = info.getInfo("contains");
984 if (contains.equals("")) {
985 return 0;
986 }
987 String [] children = contains.split(";");
988 return children.length;
989 }
990
991}
Note: See TracBrowser for help on using the repository browser.