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

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

Lots of changes. Mainly to do with removing this.doc from everywhere. Document is not thread safe. Now we tend to create a new Document everytime we are starting a new page/message etc. in service this.desc_doc is available as teh document to create service info stuff. But it should only be used for this and not for other messages. newDOM is now static for XMLConverter. method param changes for some GSXML methods.

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