source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/OAIPMH.java@ 28861

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

removed use of this.doc. Some static strings now coming from GSXML not OAIXML. OAIXML creating error elements has changed syntax. Added method to set up set info. includes any super set that this collection may belong to.

File size: 31.5 KB
Line 
1/*
2 * OAIPMH.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// Greenstone classes
22import org.greenstone.gsdl3.core.GSException;
23import org.greenstone.gsdl3.util.GSXML;
24import org.greenstone.gsdl3.util.OAIXML;
25import org.greenstone.gsdl3.util.OID;
26import org.greenstone.gsdl3.util.GSFile;
27import org.greenstone.gsdl3.util.XMLConverter;
28
29import org.greenstone.gsdl3.util.SimpleCollectionDatabase;
30import org.greenstone.gsdl3.util.DBInfo;
31// XML classes
32import org.w3c.dom.Document;
33import org.w3c.dom.Element;
34import org.w3c.dom.NodeList;
35
36// General Java classes
37import java.io.File;
38import java.util.StringTokenizer;
39import java.util.Vector;
40import java.util.Set;
41import java.util.Iterator;
42import java.util.ArrayList;
43import java.util.Date;
44import java.util.HashMap;
45import java.util.Map.Entry;
46
47import org.apache.log4j.Logger;
48
49/** Implements the oai metadata retrieval service for GS3 collections.
50 * Dig into each collection's database and retrieve the metadata
51 *
52 */
53
54public class OAIPMH extends ServiceRack {
55
56 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.OAIPMH.class.getName());
57
58 protected SimpleCollectionDatabase coll_db = null;
59
60 protected String site_name = "";
61 protected String coll_name = "";
62
63 // set this up during configure
64 protected Element list_sets_response = null;
65
66 /** constructor */
67 public OAIPMH() {
68
69 }
70
71 public void cleanUp() {
72 super.cleanUp();//??
73 this.coll_db.closeDatabase();
74 }
75 /** configure this service
76 info is the OAIPMH service rack from collectionConfig.xml, and
77 extra_info is buildConfig.xml */
78 public boolean configure(Element info, Element extra_info) {
79 if (!super.configure(info, extra_info)){
80 logger.info("Configuring ServiceRack.java returns false.");
81 return false;
82 }
83
84 Document doc = this.converter.newDOM();
85 this.short_service_info = doc.createElement(GSXML.SERVICE_ELEM + GSXML.LIST_MODIFIER);
86 //get the names from ServiceRack.java
87 this.site_name = this.router.getSiteName();
88 this.coll_name = this.cluster_name;
89
90 logger.info("Configuring OAIPMH...");
91
92 this.config_info = info;
93
94 // the index stem is either specified in the buildConfig.xml file (extra_info) or uses the collection name
95 Element metadata_list = (Element) GSXML.getChildByTagName(extra_info, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
96 String index_stem = "";
97 String infodb_type = "";
98 if (metadata_list != null) {
99
100 Element index_stem_elem = (Element) GSXML.getNamedElement(metadata_list, GSXML.METADATA_ELEM, GSXML.NAME_ATT, "indexStem");
101
102 if (index_stem_elem != null) {
103 index_stem = GSXML.getNodeText(index_stem_elem);
104 }
105
106 Element infodb_type_elem = (Element) GSXML.getNamedElement(metadata_list, GSXML.METADATA_ELEM, GSXML.NAME_ATT, "infodbType");
107 if (infodb_type_elem != null) {
108 infodb_type = GSXML.getNodeText(infodb_type_elem);
109 }
110
111 }
112
113 if (index_stem == null || index_stem.equals("")) {
114 index_stem = this.cluster_name;
115 }
116 if (infodb_type == null || infodb_type.equals("")) {
117 infodb_type = "gdbm"; // the default
118 }
119
120 coll_db = new SimpleCollectionDatabase(infodb_type);
121 if (!coll_db.databaseOK()) {
122 logger.error("Couldn't create the collection database of type "+infodb_type);
123 return false;
124 }
125
126 // Open database for querying
127 String coll_db_file = GSFile.collectionDatabaseFile(this.site_home, this.cluster_name, index_stem, infodb_type);
128 if (!this.coll_db.openDatabase(coll_db_file, SimpleCollectionDatabase.READ)) {
129 logger.error("Could not open collection database!");
130 return false;
131 }
132
133 // work out what sets this collection has. Will usually contain the collection itself, optional super collection, and maybe subcolls if appropriate classifiers are present.
134 configureSetInfo();
135 // the short_service_info is used by the message router to find the method names,
136 //so we just use the doc variable in class ServiceRack to create the xml; but
137 // in each method we will use OAIXMLto create the response xml
138 // set up short_service_info_ - just the name
139
140 Element list_records = doc.createElement(GSXML.SERVICE_ELEM);
141 list_records.setAttribute(GSXML.NAME_ATT, OAIXML.LIST_RECORDS);
142 list_records.setAttribute(GSXML.TYPE_ATT, "oai");
143 this.short_service_info.appendChild(list_records);
144
145 Element list_identifiers = doc.createElement(GSXML.SERVICE_ELEM);
146 list_identifiers.setAttribute(GSXML.NAME_ATT, OAIXML.LIST_IDENTIFIERS);
147 list_identifiers.setAttribute(GSXML.TYPE_ATT, "oai");
148 this.short_service_info.appendChild(list_identifiers);
149
150 Element list_sets = doc.createElement(GSXML.SERVICE_ELEM);
151 list_sets.setAttribute(GSXML.NAME_ATT, OAIXML.LIST_SETS);
152 list_sets.setAttribute(GSXML.TYPE_ATT, "oai");
153 this.short_service_info.appendChild(list_sets);
154
155 Element list_metadata_formats = doc.createElement(GSXML.SERVICE_ELEM);
156 list_metadata_formats.setAttribute(GSXML.NAME_ATT, OAIXML.LIST_METADATA_FORMATS);
157 list_metadata_formats.setAttribute(GSXML.TYPE_ATT, "oai");
158 this.short_service_info.appendChild(list_metadata_formats);
159
160 Element get_record = doc.createElement(GSXML.SERVICE_ELEM);
161 get_record.setAttribute(GSXML.NAME_ATT, OAIXML.GET_RECORD);
162 get_record.setAttribute(GSXML.TYPE_ATT, "oai");
163 this.short_service_info.appendChild(get_record);
164
165 return true;
166 }
167
168 /** returns a specific service description */
169 public Element getServiceDescription(String service_id, String lang, String subset) {
170
171 Document doc = this.converter.newDOM();
172 if (service_id.equals(OAIXML.LIST_RECORDS)) {
173 Element list_records = doc.createElement(GSXML.SERVICE_ELEM);
174 list_records.setAttribute(GSXML.NAME_ATT, OAIXML.LIST_RECORDS);
175 list_records.setAttribute(GSXML.TYPE_ATT, "oai");
176 return list_records;
177 }
178
179 if (service_id.equals(OAIXML.LIST_IDENTIFIERS)) {
180 Element list_identifiers = doc.createElement(GSXML.SERVICE_ELEM);
181 list_identifiers.setAttribute(GSXML.NAME_ATT, OAIXML.LIST_IDENTIFIERS);
182 list_identifiers.setAttribute(GSXML.TYPE_ATT, "oai");
183 return list_identifiers;
184 }
185 if (service_id.equals(OAIXML.LIST_SETS)) {
186 Element list_sets = doc.createElement(GSXML.SERVICE_ELEM);
187 list_sets.setAttribute(GSXML.NAME_ATT, OAIXML.LIST_SETS);
188 list_sets.setAttribute(GSXML.TYPE_ATT, "oai");
189 return list_sets;
190 }
191 if (service_id.equals(OAIXML.LIST_METADATA_FORMATS)) {
192 Element list_metadata_formats = doc.createElement(GSXML.SERVICE_ELEM);
193 list_metadata_formats.setAttribute(GSXML.NAME_ATT, OAIXML.LIST_METADATA_FORMATS);
194 list_metadata_formats.setAttribute(GSXML.TYPE_ATT, "oai");
195 return list_metadata_formats;
196 }
197
198 if (service_id.equals(OAIXML.GET_RECORD)) {
199 Element get_record = doc.createElement(GSXML.SERVICE_ELEM);
200 get_record.setAttribute(GSXML.NAME_ATT, OAIXML.GET_RECORD);
201 get_record.setAttribute(GSXML.TYPE_ATT, "oai");
202 return get_record;
203 }
204
205 return null;
206 }
207 // /** return the metadata information about this set of the repository */
208 // protected Element processIdentify(Element req) {
209 // return null;
210 // }
211 /** return the metadata information */
212 protected Element processListSets(Element req) {
213 return list_sets_response;
214 }
215 /** return the metadata information */
216 protected Element processGetRecord(Element req) {
217 /** arguments:
218 identifier: required
219 metadataPrefix: required
220 * Exceptions: badArgument; cannotDisseminateFormat; idDoesNotExist
221 */
222 NodeList params = GSXML.getChildrenByTagName(req, GSXML.PARAM_ELEM);
223 HashMap<String, String> param_map = GSXML.getParamMap(params);
224
225 String prefix = param_map.get(OAIXML.METADATA_PREFIX);
226 if (prefix == null || prefix.equals("")) {
227 //Just a double-check
228 logger.error("the value of metadataPrefix att is not present in the request.");
229 return OAIXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
230 }
231
232 Element metadata_format = getMetadataFormatElement(prefix);
233 if(metadata_format == null) {
234 logger.error("metadata prefix is not supported.");
235 return OAIXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
236 }
237
238 String oid = param_map.get(OAIXML.OID); // TODO should this be identifier???
239
240 //get a DBInfo object of the identifier; if this identifier is not present in the database,
241 // null is returned.
242 DBInfo info = this.coll_db.getInfo(oid);
243 if (info == null) {
244 logger.error("OID: " + oid + " is not present in the database.");
245 return OAIXML.createErrorResponse(OAIXML.ID_DOES_NOT_EXIST, "");
246 }
247
248 Document doc = this.converter.newDOM();
249 ArrayList<String> keys = new ArrayList<String>(info.getKeys());
250 String oailastmodified = "";
251 if(keys.contains(OAIXML.OAI_LASTMODIFIED)) {
252 oailastmodified = info.getInfo(OAIXML.OAI_LASTMODIFIED);
253 oailastmodified = OAIXML.getTime(Long.parseLong(oailastmodified)*1000); // java wants dates in milliseconds
254 }
255
256 Element get_record_response = doc.createElement(GSXML.RESPONSE_ELEM);
257 Element get_record = doc.createElement(OAIXML.GET_RECORD);
258 get_record_response.appendChild(get_record);
259 Element record = doc.createElement(OAIXML.RECORD);
260 //compose the header element
261 record.appendChild(createHeaderElement(doc, oid, oailastmodified));
262 //compose the metadata element
263 record.appendChild(createMetadataElement(doc, prefix, info, metadata_format));
264 get_record.appendChild(record);
265 return get_record_response;
266 }
267 /** return a list of identifiers */
268 protected Element processListIdentifiers(Element req) {
269 /** arguments:
270 metadataPrefix: required
271 * from: optional
272 * until: optional
273 * set: optional
274 * resumptionToken: exclusive and optional (ignored as it has been handled by OAIReceptionist)
275 * Exceptions: badArgument; cannotDisseminateFormat; idDoesNotExist
276 */
277 NodeList params = GSXML.getChildrenByTagName(req, GSXML.PARAM_ELEM);
278
279 if(params.getLength() == 0) {
280 logger.error("must at least have the metadataPrefix parameter, can't be none");
281 return OAIXML.createErrorResponse(OAIXML.BAD_ARGUMENT, "");
282 }
283
284 HashMap<String, String> param_map = GSXML.getParamMap(params);
285
286 String prefix = "";
287 Date from_date = null;
288 Date until_date = null;
289
290 if(param_map.containsKey(OAIXML.METADATA_PREFIX) == false) {
291 //Just a double-check
292 logger.error("A param element containing the metadataPrefix is not present.");
293 return OAIXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
294 }
295 prefix = param_map.get(OAIXML.METADATA_PREFIX);
296 if (prefix == null || prefix.equals("")) {
297 //Just a double-check
298 logger.error("the value of metadataPrefix att is not present in the request.");
299 return OAIXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
300 }
301
302 if(param_map.containsKey(OAIXML.FROM)) {
303 String from = param_map.get(OAIXML.FROM);
304 from_date = OAIXML.getDate(from);
305 }
306 if(param_map.containsKey(OAIXML.UNTIL)) {
307 String until = param_map.get(OAIXML.UNTIL);
308 until_date = OAIXML.getDate(until);
309 }
310
311 Element metadata_format = getMetadataFormatElement(prefix);
312 if(metadata_format == null) {
313 logger.error("metadata prefix is not supported.");
314 return OAIXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
315 }
316 ArrayList<String> oid_list = getChildrenIds(OAIXML.BROWSELIST);
317 if (oid_list == null) {
318 logger.error("No matched records found in collection: browselist is empty");
319 return OAIXML.createErrorResponse(OAIXML.NO_RECORDS_MATCH, "");
320 }
321 // all validation is done
322
323 Document doc = this.converter.newDOM();
324 Element list_identifiers_response = doc.createElement(GSXML.RESPONSE_ELEM);
325 Element list_identifiers = doc.createElement(OAIXML.LIST_IDENTIFIERS);
326 list_identifiers_response.appendChild(list_identifiers);
327
328 for(int i=0; i<oid_list.size(); i++) {
329 String oid = oid_list.get(i);
330 DBInfo info = this.coll_db.getInfo(oid);
331 if (info == null) {
332 logger.error("Database does not contains information about oid: " +oid);
333 continue;
334 }
335 ArrayList<String> keys = new ArrayList<String>(info.getKeys());
336 String oailastmodified = "";
337 if(keys.contains(OAIXML.OAI_LASTMODIFIED)) {
338 oailastmodified = info.getInfo(OAIXML.OAI_LASTMODIFIED);
339 oailastmodified = OAIXML.getTime(Long.parseLong(oailastmodified)*1000); // java wants dates in milliseconds
340 }
341
342 Date this_date = OAIXML.getDate(oailastmodified);
343 if (from_date != null) {
344 if(this_date.before(from_date)) {
345 continue;
346 }
347 }
348 if (until_date != null) {
349 if (this_date.after(until_date)) {
350 continue;
351 }
352 }
353 //compose the header element and append it
354 list_identifiers.appendChild(createHeaderElement(doc, oid, oailastmodified));
355 }//end of for(int i=0; i<oid_list.size(); i++) of doing thru each record
356
357 return list_identifiers_response;
358 }
359 /** return a list of records */
360 protected Element processListRecords(Element req) {
361 /** the request sent here may contain optional 'from', 'untill', 'metadataPrefix',
362 * and 'resumptionToken' params. see doListSets() in OAIReceptionist.
363 * if the request contains 'resumptionToken' then it should have been handled by the
364 * OAIReceptionist. Therefore, the request sent here must not contain 'resumptionToken'
365 * argument but a 'metadataPrefix' param. The OAIReceptionist makes sure of this.
366 */
367 NodeList params = GSXML.getChildrenByTagName(req, GSXML.PARAM_ELEM);
368
369 if(params.getLength() == 0) {
370 logger.error("must at least have the metadataPrefix parameter, can't be none");
371 return OAIXML.createErrorResponse(OAIXML.BAD_ARGUMENT, "");
372 }
373
374 HashMap<String, String> param_map = GSXML.getParamMap(params);
375
376 String prefix = "";
377 Date from_date = null;
378 Date until_date = null;
379
380 if(param_map.containsKey(OAIXML.METADATA_PREFIX) == false) {
381 //Just a double-check
382 logger.error("A param element containing the metadataPrefix is not present.");
383 return OAIXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
384 }
385 prefix = param_map.get(OAIXML.METADATA_PREFIX);
386 if (prefix == null || prefix.equals("")) {
387 //Just a double-check
388 logger.error("the value of metadataPrefix att is not present in the request.");
389 return OAIXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
390 }
391
392 if(param_map.containsKey(OAIXML.FROM)) {
393 String from = param_map.get(OAIXML.FROM);
394 from_date = OAIXML.getDate(from);
395 }
396 if(param_map.containsKey(OAIXML.UNTIL)) {
397 String until = param_map.get(OAIXML.UNTIL);
398 until_date = OAIXML.getDate(until);
399 }
400 Element metadata_format = getMetadataFormatElement(prefix);
401 if(metadata_format == null) {
402 logger.error("metadata prefix is not supported.");
403 return OAIXML.createErrorResponse(OAIXML.CANNOT_DISSEMINATE_FORMAT, "");
404 }
405
406 //get a list of identifiers (it contains a list of strings)
407 ArrayList<String> oid_list = getChildrenIds(OAIXML.BROWSELIST);
408 if (oid_list == null) {
409 logger.error("No matched records found in collection: browselist is empty");
410 return OAIXML.createErrorResponse(OAIXML.NO_RECORDS_MATCH, "");
411 }
412 // all validation is done
413
414 Document doc = this.converter.newDOM();
415 Element list_records_response = doc.createElement(GSXML.RESPONSE_ELEM);
416 Element list_records = doc.createElement(OAIXML.LIST_RECORDS);
417 list_records_response.appendChild(list_records);
418 for(int i=0; i<oid_list.size(); i++) {
419 String oid = oid_list.get(i);
420 DBInfo info = this.coll_db.getInfo(oid);
421 if (info == null) {
422 logger.error("Database does not contains information about oid: " +oid);
423 continue;
424 }
425 ArrayList<String> keys = new ArrayList<String>(info.getKeys());
426 String oailastmodified = "";
427 if(keys.contains(OAIXML.OAI_LASTMODIFIED)) {
428 oailastmodified = info.getInfo(OAIXML.OAI_LASTMODIFIED);
429 oailastmodified = OAIXML.getTime(Long.parseLong(oailastmodified)*1000); // java wants dates in milliseconds
430 }
431
432 Date this_date = OAIXML.getDate(oailastmodified);
433 if (from_date != null) {
434 if(this_date.before(from_date)) {
435 continue;
436 }
437 }
438 if (until_date != null) {
439 if (this_date.after(until_date)) {
440 continue;
441 }
442 }
443
444 Element record = doc.createElement(OAIXML.RECORD);
445 list_records.appendChild(record);
446 //compose the header element
447 record.appendChild(createHeaderElement(doc, oid, oailastmodified));
448 //compose the metadata element
449 record.appendChild(createMetadataElement(doc, prefix, info, metadata_format));
450
451 }//end of for(int i=0; i<oid_list.size(); i++) of doing thru each record
452
453 return list_records_response;
454 }
455
456 // have implemented setDescription as an element, instead of a container containing metadata
457 private boolean configureSetInfo() {
458
459 Document doc = this.converter.newDOM();
460 this.list_sets_response = doc.createElement(GSXML.RESPONSE_ELEM);
461 Element list_sets_elem = doc.createElement(OAIXML.LIST_SETS);
462 this.list_sets_response.appendChild(list_sets_elem);
463 String set_name = this.coll_name;
464 String set_description = null;
465 Element name_elem = (Element)GSXML.getChildByTagName(this.config_info, OAIXML.SET_NAME);
466 if (name_elem!=null) {
467 set_name = GSXML.getNodeText(name_elem);
468 if (set_name.equals("")) {
469 set_name = this.coll_name; // default to coll name if can't find one
470 }
471 }
472 Element description_elem = (Element)GSXML.getChildByTagName(this.config_info, OAIXML.SET_DESCRIPTION);
473 if (description_elem!=null) {
474 set_description = GSXML.getNodeText(description_elem);
475 if (set_description.equals("")) {
476 set_description = null;
477 }
478 }
479 Element coll_set = OAIXML.createSet(doc, this.coll_name, set_name, set_description);
480 list_sets_elem.appendChild(coll_set);
481
482 // are we part of any super sets?
483 NodeList super_set_list = GSXML.getChildrenByTagName(this.config_info, OAIXML.OAI_SUPER_SET);
484 for (int i=0; i<super_set_list.getLength(); i++) {
485 String super_name = ((Element)super_set_list.item(i)).getAttribute(GSXML.NAME_ATT);
486 if (super_name != null && !super_name.equals("")) {
487 list_sets_elem.appendChild(OAIXML.createSet(doc, super_name, super_name, null));
488 }
489 }
490 return true;
491 }
492 /** get the metadataFormat element from the collectionConfig.xml containing the specified metadata prefix.
493 * return null if not found.
494 */
495 private Element getMetadataFormatElement(String prefix) {
496 Element list_meta_format = (Element)GSXML.getChildByTagName(this.config_info, OAIXML.LIST_METADATA_FORMATS);
497 Element metadata_format = GSXML.getNamedElement(list_meta_format, OAIXML.METADATA_FORMAT, OAIXML.METADATA_PREFIX, prefix);
498 return metadata_format;
499 }
500 /** create the metadata element used when processing ListRecords/GetRecord requests
501 */
502 private Element createMetadataElement(Document doc, String prefix, DBInfo info, Element metadata_format) {
503 //the prefix string is in the form: oai_dc, for example.
504 String prfx_str = "";
505 //the metadata namespace used to retrieve metadata in the repository
506 //For example, if the prefix is like 'oai_ex' then we used 'ex' to get the metadata
507 //Normally we would use 'dc' to find metadata.
508 String meta_ns = "";
509 if(prefix.equals(OAIXML.OAI_DC)) {
510 if(OAIXML.oai_version.equals(OAIXML.OAI_VERSION2)) {
511 prfx_str = prefix + ":" + OAIXML.DC;
512 } else {
513 prfx_str = OAIXML.DC;//oai version 1
514 }
515 meta_ns = OAIXML.DC;
516 } else {
517 prfx_str = prefix.substring(prefix.indexOf("_") + 1);
518 meta_ns = prfx_str;
519 }
520 //create the <metadata> element
521 //OAIXML.oai_version is read from OAIConfig.xml and its default value is "2.0"
522 Element metadata = doc.createElement(OAIXML.METADATA);
523 Element prfx_str_elem = OAIXML.getMetadataPrefixElement(doc, prfx_str, OAIXML.oai_version);
524 metadata.appendChild(prfx_str_elem);
525 String[] metadata_names = getMetadataNameMapping(metadata_format);
526 HashMap meta_map = getInfoByNames(info, metadata_names);
527
528 // if there's no dc:identifier already after the mapping, we'll add it in
529 if(!meta_map.containsKey(OAIXML.DC+":identifier")) { // dc:identifier OAIXML.IDENTIFIER
530 outputCustomMetadata(meta_map, info, OAIXML.DC+":identifier");
531 }
532
533
534 if (meta_map == null) {
535 return metadata;
536 }
537 ArrayList meta_list = new ArrayList(meta_map.entrySet());
538 for (int j=0; j<meta_list.size(); j++) {
539 Entry men = (Entry)meta_list.get(j);
540 String meta_name = (String)men.getKey();
541 //meta_name = meta_name.replace('.', ':'); // namespace separator should be : for oai
542 String meta_value = (String)men.getValue();
543 Element e = doc.createElement(meta_name);
544 GSXML.setNodeText(e, meta_value);
545 prfx_str_elem.appendChild(e);
546 }
547
548 return metadata;
549 }
550 /** create a header element used when processing requests like ListRecords/GetRecord/ListIdentifiers
551 */
552 private Element createHeaderElement(Document doc, String oid, String oailastmodified) {
553 Element header = doc.createElement(OAIXML.HEADER);
554 Element identifier = doc.createElement(OAIXML.IDENTIFIER);
555 //GSXML.setNodeText(identifier, site_name + ":" + coll_name + ":" + oid);
556 GSXML.setNodeText(identifier, coll_name + ":" + oid);
557 header.appendChild(identifier);
558 Element set_spec = doc.createElement(OAIXML.SET_SPEC);
559 //GSXML.setNodeText(set_spec, site_name + ":" + coll_name);
560 GSXML.setNodeText(set_spec, coll_name);
561 header.appendChild(set_spec);
562 Element datestamp = doc.createElement(OAIXML.DATESTAMP);
563 GSXML.setNodeText(datestamp, oailastmodified);
564 header.appendChild(datestamp);
565 return header;
566 }
567 /** return the metadata information */
568 protected Element processListMetadataFormats(Element req) {
569 // the request sent here must contain an OID. see doListMetadataFormats() in OAIReceptionist
570 Element param = GSXML.getNamedElement(req, GSXML.PARAM_ELEM, GSXML.NAME_ATT, OAIXML.OID);
571 if (param == null) {
572 logger.error("An element containing the OID attribute not is present.");
573 return OAIXML.createErrorResponse(OAIXML.ID_DOES_NOT_EXIST, "");
574 }
575 String oid = param.getAttribute(GSXML.VALUE_ATT);
576 if (oid == null || oid.equals("")) {
577 logger.error("No OID is present in the request.");
578 return OAIXML.createErrorResponse(OAIXML.ID_DOES_NOT_EXIST, "");
579 }
580 ArrayList<String> oid_list = getChildrenIds(OAIXML.BROWSELIST);
581 if (oid_list == null || oid_list.contains(oid) == false) {
582 logger.error("OID: " + oid + " is not present in the database.");
583 Element e= OAIXML.createErrorResponse(OAIXML.ID_DOES_NOT_EXIST, "");
584// logger.error((new XMLConverter()).getPrettyString (e));
585 return e;
586 }
587
588 DBInfo info = null;
589 info = this.coll_db.getInfo(oid);
590 if (info == null) { //just double check
591 return OAIXML.createErrorResponse(OAIXML.OAI_SERVICE_UNAVAILABLE, "");
592 }
593
594 NodeList meta_list = getMetadataFormatList();
595 if (meta_list == null || meta_list.getLength() == 0) {
596 logger.error("No metadata format is present in collectionConfig.xml");
597 return OAIXML.createErrorResponse(OAIXML.NO_METADATA_FORMATS, "");
598 }
599
600 Document doc = this.converter.newDOM();
601 Element list_metadata_formats_response = doc.createElement(GSXML.RESPONSE_ELEM);
602
603 Element list_metadata_formats = doc.createElement(OAIXML.LIST_METADATA_FORMATS);
604 list_metadata_formats_response.appendChild(list_metadata_formats);
605 boolean has_meta_format = false;
606
607 for (int i=0; i<meta_list.getLength(); i++) {
608 Element metadata_format = (Element)meta_list.item(i);
609 String[] metadata_names = getMetadataNameMapping(metadata_format);
610 if (containsMetadata(info, metadata_names) == true) {
611 has_meta_format = true;
612 // TODO, can we do this in an easier way??
613 Element meta_fmt = doc.createElement(OAIXML.METADATA_FORMAT);
614 GSXML.copyElement(meta_fmt, metadata_format, OAIXML.METADATA_PREFIX);
615 GSXML.copyElement(meta_fmt, metadata_format, OAIXML.METADATA_NAMESPACE);
616 GSXML.copyElement(meta_fmt, metadata_format, OAIXML.SCHEMA);
617 list_metadata_formats.appendChild(meta_fmt);
618 }
619 }//end of for loop
620 if (has_meta_format == false) {
621 logger.error("Specified metadata names are not contained in the database.");
622 return OAIXML.createErrorResponse(OAIXML.NO_METADATA_FORMATS, "");
623 } else {
624 return list_metadata_formats_response;
625 }
626 }
627
628 /** return the ListMetadataFormats element in collectionConfig.xml
629 * Currently, it will only contain one metadata format: oai_dc
630 */
631 protected NodeList getMetadataFormatList() {
632 Element list_meta_formats = (Element)GSXML.getChildByTagName(this.config_info, OAIXML.LIST_METADATA_FORMATS);
633 return GSXML.getChildrenByTagName(list_meta_formats, OAIXML.METADATA_FORMAT);
634 }
635 /** @param metadata_format - the metadataFormat element in collectionConfig.xml
636 */
637 protected String[] getMetadataNameMapping(Element metadata_format) {
638
639 String[] names = OAIXML.getMetadataMapping(metadata_format);
640 if (names != null) {
641 return names;
642 }
643 logger.info("No metadata mappings are provided in collectionConfig.xml. Try for global mapping");
644 names = OAIXML.getGlobalMetadataMapping(metadata_format.getAttribute(OAIXML.METADATA_PREFIX));
645 return names;
646 }
647
648 /** returns a list of the child ids in order, null if no children */
649 protected ArrayList<String> getChildrenIds(String node_id) {
650 DBInfo info = this.coll_db.getInfo(node_id);
651 if (info == null) {
652 return null;
653 }
654
655 String contains = info.getInfo("contains");
656 if (contains.equals("")) {
657 return null;
658 }
659 ArrayList<String> children = new ArrayList<String>();
660 StringTokenizer st = new StringTokenizer(contains, ";");
661 while (st.hasMoreTokens()) {
662 String child_id = st.nextToken().replaceAll("\"", node_id);
663 children.add(child_id);
664 }
665 return children;
666 }
667 /**method to check whether any of the 'metadata_names' is contained in the 'info'.
668 * The name may be in the form: <name>,<mapped name>, in which the mapped name is
669 * optional. The mapped name is looked up in the DBInfo; if not present, use the first
670 * name which is mendatory.
671 */
672 protected boolean containsMetadata(DBInfo info, String[] metadata_names) {
673 if (metadata_names == null) return false;
674 logger.info("checking metadata names in db.");
675 for(int i=0; i<metadata_names.length; i++) {
676 int index = metadata_names[i].indexOf(",");
677 String meta_name = (index == -1) ? metadata_names[i] :
678 metadata_names[i].substring(index + 1);
679
680 if(info.getInfo(meta_name).equals("") == false) {
681 return true;
682 }
683 }
684 return false;
685 }
686 /** @param keys - contains a list of keys in string format.
687 * Here is a typical record in the collection database, 'keys' contains the values in <...>:
688 *----------------------------------------------------------------------
689[HASH01a84acb0f1aad2380493b3a]
690<doctype>doc
691<hastxt>1
692<Language>en
693<Encoding>windows_1252
694<Plugin>HTMLPlug
695<FileSize>205093
696<Source>wb34te.htm
697<hascover>1
698<dls.Organization>World Bank
699<dls.Title>Development in practice: Toward Gender Equality (wb34te)
700<dls.Language>English
701<dls.AZList>A-B-C-D-E-F-G-H-I-J-K-L-M-N-O-P-Q-R-S-T-U-V-W-X-Y-Z
702<dls.Subject>Women, gender and development, women's organizations
703<dls.Keyword>achieve gender equality
704<URL>http://wb34te/wb34te.htm
705<Title>Development in practice: Toward Gender Equality
706<lastmodified>1178245194
707<assocfilepath>HASH01a8.dir
708<memberof>CL3
709<archivedir>HASH01a8.dir
710<thistype>VList
711<childtype>VList
712<contains>".1;".2;".3;".4;".5;".6;".7;".8;".9
713<docnum>349
714<oailastmodified>1303283795
715<lastmodifieddate>20110412
716<oailastmodifieddate>20110420
717----------------------------------------------------------------------
718 */
719 public String[] getMetadata(DBInfo info, String names) {
720 String[] name_value = new String[2];
721 ArrayList<String> keys = new ArrayList<String>(info.getKeys());
722 for (int i=0; i<keys.size(); i++) {
723 String key = keys.get(i);
724 String first_name = "";
725 String second_name = "";
726 int index = names.indexOf(",");
727 if(index != -1) {
728 first_name = names.substring(0, index);
729 second_name = names.substring(index + 1);
730 } else {
731 first_name = second_name = names;
732 }
733 if(key.equals(second_name)) {
734 String meta_value = info.getInfo(key);
735 name_value[0] = first_name;
736 name_value[1] = meta_value;
737 return name_value;
738 }
739 }
740 return null;
741 }
742 protected HashMap getInfoByNames(DBInfo info, String[] metadata_names) {
743
744 if (metadata_names == null) {
745 return null;
746 }
747 HashMap<String, String> map = new HashMap<String, String>();
748 boolean empty_map = true;
749
750 for(int i=0; i<metadata_names.length; i++) {
751 String[] name_value = getMetadata(info, metadata_names[i]);
752 if(name_value != null) {
753 map.put(name_value[0], name_value[1]);
754 empty_map = false;
755 }
756 }
757 return (empty_map == true) ? null : map;
758 }
759
760 // GS3 version of GS2's runtime-src/src/oaiservr/dublincore.cpp function output_custom_metadata
761 protected void outputCustomMetadata(HashMap meta_map, DBInfo info, String dc_identifier) {
762
763 // try gs.OAIResourceURL, else srclinkFile, else the GS version of the document
764 String identifier_value = info.getInfo(OAIXML.GS_OAI_RESOURCE_URL);
765
766 if(identifier_value.equals("")) {
767 String url = OAIXML.getBaseURL(); // e.g. e.g. http://host:port/greenstone3/library/oaiserver
768
769 identifier_value = info.getInfo("srclinkFile");
770 if(identifier_value.equals(""))
771 {
772 // no source file to link to, so link to the GS version of the document (need to use URL-style slashes)
773 // e.g. http://host:port/greenstone3/library/collection/lucene-jdbm-demo/document/HASH014602ec89e16b7d431c7627
774
775 identifier_value = url.replace("oaiserver", "library") + "collection/" + this.coll_name + "/document/" + info.getInfo("identifier"); // OID
776 }
777 else // use srclinkFile
778 {
779 // e.g. http://host:port/greenstone3/sites/localsite/collect/backdrop/index/assoc/D0.dir/Cat.jpg
780 identifier_value = url.replace("oaiserver", "") + "sites/" + this.site_name
781 + "/collect/" + this.coll_name + "/index/assoc/"
782 + info.getInfo("assocfilepath") + "/" + identifier_value; // srclinkFile
783 }
784 } // else use gs.OAIResourceURL as-is
785
786 //logger.info("**** dc:identifier: " + identifier_value);
787
788 meta_map.put(dc_identifier, identifier_value);
789 }
790}
791
792
Note: See TracBrowser for help on using the repository browser.