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