KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dspace > app > oai > DSpaceOAICatalog


1 /*
2  * DSpaceOAICatalog.java
3  *
4  * Version: $Revision: 1.19 $
5  *
6  * Date: $Date: 2006/11/24 00:44:02 $
7  *
8  * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
9  * Institute of Technology. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are
13  * met:
14  *
15  * - Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  *
18  * - Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution.
21  *
22  * - Neither the name of the Hewlett-Packard Company nor the name of the
23  * Massachusetts Institute of Technology nor the names of their
24  * contributors may be used to endorse or promote products derived from
25  * this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
34  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38  * DAMAGE.
39  */

40 package org.dspace.app.oai;
41
42 import java.sql.SQLException JavaDoc;
43 import java.text.ParseException JavaDoc;
44 import java.util.HashMap JavaDoc;
45 import java.util.Iterator JavaDoc;
46 import java.util.LinkedList JavaDoc;
47 import java.util.List JavaDoc;
48 import java.util.Map JavaDoc;
49 import java.util.NoSuchElementException JavaDoc;
50 import java.util.Properties JavaDoc;
51 import java.util.StringTokenizer JavaDoc;
52 import java.util.Vector JavaDoc;
53
54 import org.apache.log4j.Logger;
55 import org.dspace.content.Collection;
56 import org.dspace.content.DSpaceObject;
57 import org.dspace.core.ConfigurationManager;
58 import org.dspace.core.Context;
59 import org.dspace.core.LogManager;
60 import org.dspace.core.Utils;
61 import org.dspace.handle.HandleManager;
62 import org.dspace.search.Harvest;
63 import org.dspace.search.HarvestedItemInfo;
64
65 import ORG.oclc.oai.server.catalog.AbstractCatalog;
66 import ORG.oclc.oai.server.verb.BadArgumentException;
67 import ORG.oclc.oai.server.verb.BadResumptionTokenException;
68 import ORG.oclc.oai.server.verb.CannotDisseminateFormatException;
69 import ORG.oclc.oai.server.verb.IdDoesNotExistException;
70 import ORG.oclc.oai.server.verb.NoItemsMatchException;
71 import ORG.oclc.oai.server.verb.NoMetadataFormatsException;
72 import ORG.oclc.oai.server.verb.NoSetHierarchyException;
73 import ORG.oclc.oai.server.verb.OAIInternalServerError;
74
75 /**
76  * This is class extends OAICat's AbstractCatalog base class to allow metadata
77  * harvesting of the metadata in DSpace via OAI-PMH 2.0.
78  *
79  * FIXME: Some CNRI Handle-specific stuff in here. Anyone wanting to use
80  * something else will need to update this code too. Sorry about that.
81  *
82  * @author Robert Tansley
83  * @version $Revision: 1.19 $
84  */

85 public class DSpaceOAICatalog extends AbstractCatalog
86 {
87     /** log4j logger */
88     private static Logger log = Logger.getLogger(DSpaceOAICatalog.class);
89
90     /** Prefix that all our OAI identifiers have */
91     public final static String JavaDoc OAI_ID_PREFIX = "oai:"
92             + ConfigurationManager.getProperty("dspace.hostname") + ":";
93
94     /** Maximum number of records returned by one request */
95     private final int MAX_RECORDS = 100;
96
97     public DSpaceOAICatalog(Properties JavaDoc properties)
98     {
99         // Don't need to do anything
100
}
101
102     /**
103      * Retrieve a list of schemaLocation values associated with the specified
104      * identifier.
105      *
106      * @param identifier
107      * the OAI identifier
108      * @return a Vector containing schemaLocation Strings
109      * @exception OAIInternalServerError
110      * signals an http status code 500 problem
111      * @exception IdDoesNotExistException
112      * the specified identifier can't be found
113      * @exception NoMetadataFormatsException
114      * the specified identifier was found but the item is flagged
115      * as deleted and thus no schemaLocations (i.e.
116      * metadataFormats) can be produced.
117      */

118     public Vector JavaDoc getSchemaLocations(String JavaDoc identifier)
119             throws OAIInternalServerError, IdDoesNotExistException,
120             NoMetadataFormatsException
121     {
122         log.info(LogManager.getHeader(null, "oai_request",
123                 "verb=getSchemaLocations,identifier="
124                         + ((identifier == null) ? "null" : identifier)));
125
126         HarvestedItemInfo itemInfo = null;
127         Context context = null;
128
129         // Get the item from the DB
130
try
131         {
132             context = new Context();
133
134             // Valid identifiers all have prefix "oai:hostname:"
135
if (identifier.startsWith(OAI_ID_PREFIX))
136             {
137                 itemInfo = Harvest.getSingle(context, identifier
138                         .substring(OAI_ID_PREFIX.length()), // Strip prefix to
139
// get raw handle
140
false);
141             }
142         }
143         catch (SQLException JavaDoc se)
144         {
145             // Log the error
146
log.warn(LogManager.getHeader(context, "database_error", ""), se);
147
148             throw new OAIInternalServerError(se.toString());
149         }
150         finally
151         {
152             if (context != null)
153             {
154                 context.abort();
155             }
156         }
157
158         if (itemInfo == null)
159         {
160             throw new IdDoesNotExistException(identifier);
161         }
162         else
163         {
164             if (itemInfo.withdrawn)
165             {
166                 throw new NoMetadataFormatsException();
167             }
168             else
169             {
170                 return getRecordFactory().getSchemaLocations(itemInfo);
171             }
172         }
173     }
174
175     /**
176      * Retrieve a list of identifiers that satisfy the specified criteria
177      *
178      * @param from
179      * beginning date using the proper granularity
180      * @param until
181      * ending date using the proper granularity
182      * @param set
183      * the set name or null if no such limit is requested
184      * @param metadataPrefix
185      * the OAI metadataPrefix or null if no such limit is requested
186      * @return a Map object containing entries for "headers" and "identifiers"
187      * Iterators (both containing Strings) as well as an optional
188      * "resumptionMap" Map. It may seem strange for the map to include
189      * both "headers" and "identifiers" since the identifiers can be
190      * obtained from the headers. This may be true, but
191      * AbstractCatalog.listRecords() can operate quicker if it doesn't
192      * need to parse identifiers from the XML headers itself. Better
193      * still, do like I do below and override
194      * AbstractCatalog.listRecords(). AbstractCatalog.listRecords() is
195      * relatively inefficient because given the list of identifiers, it
196      * must call getRecord() individually for each as it constructs its
197      * response. It's much more efficient to construct the entire
198      * response in one fell swoop by overriding listRecords() as I've
199      * done here.
200      * @exception OAIInternalServerError
201      * signals an http status code 500 problem
202      * @exception NoSetHierarchyException
203      * the repository doesn't support sets.
204      * @exception CannotDisseminateFormatException
205      * the metadata format specified is not supported by your
206      * repository.
207      */

208     public Map JavaDoc listIdentifiers(String JavaDoc from, String JavaDoc until, String JavaDoc set,
209             String JavaDoc metadataPrefix) throws OAIInternalServerError,
210             NoSetHierarchyException, NoItemsMatchException,
211             CannotDisseminateFormatException, BadArgumentException
212     {
213         log
214                 .info(LogManager.getHeader(null, "oai_request",
215                         "verb=listIdentifiers,from="
216                                 + ((from == null) ? "null" : from)
217                                 + ",until="
218                                 + ((until == null) ? "null" : until)
219                                 + ",set="
220                                 + ((set == null) ? "null" : set)
221                                 + ",metadataPrefix="
222                                 + ((metadataPrefix == null) ? "null"
223                                         : metadataPrefix)));
224
225         // We can produce oai_dc and simple DC for all items, so just return IDs
226
Context context = null;
227
228         // Lists to put results in
229
List JavaDoc headers = new LinkedList JavaDoc();
230         List JavaDoc identifiers = new LinkedList JavaDoc();
231
232         try
233         {
234             context = new Context();
235
236             // Get the relevant OAIItemInfo objects to make headers
237
Collection scope = resolveSet(context, set);
238             List JavaDoc itemInfos = Harvest.harvest(context, scope, from, until, 0, 0, // Everything
239
// for
240
// now
241
false, true, true);
242
243             // No Item objects, but we need to know collections they're in and
244
// withdrawn items
245
if (itemInfos.size() == 0)
246             {
247                 log.info(LogManager.getHeader(null, "oai_error",
248                         "no_items_match"));
249                 throw new NoItemsMatchException();
250             }
251
252             // Build up lists of headers and identifiers
253
Iterator JavaDoc i = itemInfos.iterator();
254
255             while (i.hasNext())
256             {
257                 HarvestedItemInfo itemInfo = (HarvestedItemInfo) i.next();
258
259                 String JavaDoc[] header = getRecordFactory().createHeader(itemInfo);
260
261                 headers.add(header[0]);
262                 identifiers.add(header[1]);
263             }
264         }
265         catch (SQLException JavaDoc se)
266         {
267             // Log the error
268
log.warn(LogManager.getHeader(context, "database_error", ""), se);
269
270             throw new OAIInternalServerError(se.toString());
271         }
272         catch (ParseException JavaDoc pe)
273         {
274             throw new OAIInternalServerError(pe.toString());
275         }
276         finally
277         {
278             if (context != null)
279             {
280                 context.abort();
281             }
282         }
283
284         // Put results in form needed to return
285
Map JavaDoc results = new HashMap JavaDoc();
286         results.put("headers", headers.iterator());
287         results.put("identifiers", identifiers.iterator());
288
289         return results;
290     }
291
292     /**
293      * Retrieve the next set of identifiers associated with the resumptionToken
294      *
295      * @param resumptionToken
296      * implementation-dependent format taken from the previous
297      * listIdentifiers() Map result.
298      * @return a Map object containing entries for "headers" and "identifiers"
299      * Iterators (both containing Strings) as well as an optional
300      * "resumptionMap" Map.
301      * @exception BadResumptionTokenException
302      * the value of the resumptionToken is invalid or expired.
303      * @exception OAIInternalServerError
304      * signals an http status code 500 problem
305      */

306     public Map JavaDoc listIdentifiers(String JavaDoc resumptionToken)
307             throws BadResumptionTokenException, OAIInternalServerError
308     {
309         // Resumption tokens not yet supported
310
throw new BadResumptionTokenException();
311     }
312
313     /**
314      * Retrieve the specified metadata for the specified identifier
315      *
316      * @param identifier
317      * the OAI identifier
318      * @param metadataPrefix
319      * the OAI metadataPrefix
320      * @return the <record/>portion of the XML response.
321      * @exception OAIInternalServerError
322      * signals an http status code 500 problem
323      * @exception CannotDisseminateFormatException
324      * the metadataPrefix is not supported by the item.
325      * @exception IdDoesNotExistException
326      * the identifier wasn't found
327      */

328     public String JavaDoc getRecord(String JavaDoc identifier, String JavaDoc metadataPrefix)
329             throws OAIInternalServerError, CannotDisseminateFormatException,
330             IdDoesNotExistException
331     {
332         log
333                 .info(LogManager.getHeader(null, "oai_request",
334                         "verb=getRecord,identifier="
335                                 + ((identifier == null) ? "null" : identifier)
336                                 + ",metadataPrefix="
337                                 + ((metadataPrefix == null) ? "null"
338                                         : metadataPrefix)));
339
340         Context context = null;
341         String JavaDoc record = null;
342         HarvestedItemInfo itemInfo = null;
343         
344         // First get the item from the DB
345
try
346         {
347             // Valid IDs start with oai:hostname:
348
if (identifier.startsWith(OAI_ID_PREFIX))
349             {
350                 context = new Context();
351
352                 /*
353                  * Try and get the item. the .substring() is to strip the
354                  * oai:(hostname): prefix to get the raw handle
355                  */

356                 itemInfo = Harvest.getSingle(context, identifier
357                         .substring(OAI_ID_PREFIX.length()), true);
358             }
359
360             if (itemInfo == null)
361             {
362                 log.info(LogManager.getHeader(null, "oai_error",
363                         "id_does_not_exist"));
364                 throw new IdDoesNotExistException(identifier);
365             }
366
367             String JavaDoc schemaURL;
368
369             if ((schemaURL = getCrosswalks().getSchemaURL(metadataPrefix)) == null)
370             {
371                 log.info(LogManager.getHeader(null, "oai_error",
372                         "cannot_disseminate_format"));
373                 throw new CannotDisseminateFormatException(metadataPrefix);
374             }
375
376             record = getRecordFactory().create(itemInfo, schemaURL,
377                     metadataPrefix);
378         }
379         catch (SQLException JavaDoc se)
380         {
381             // Log the error
382
log.warn(LogManager.getHeader(context, "database_error", ""), se);
383
384             throw new OAIInternalServerError(se.toString());
385         }
386         finally
387         {
388             if (context != null)
389             {
390                 context.abort();
391             }
392         }
393
394         return record;
395     }
396
397     /**
398      * Retrieve a list of records that satisfy the specified criteria. Note,
399      * though, that unlike the other OAI verb type methods implemented here,
400      * both of the listRecords methods are already implemented in
401      * AbstractCatalog rather than abstracted. This is because it is possible to
402      * implement ListRecords as a combination of ListIdentifiers and GetRecord
403      * combinations. Nevertheless, I suggest that you override both the
404      * AbstractCatalog.listRecords methods here since it will probably improve
405      * the performance if you create the response in one fell swoop rather than
406      * construct it one GetRecord at a time.
407      *
408      * @param from
409      * beginning date using the proper granularity
410      * @param until
411      * ending date using the proper granularity
412      * @param set
413      * the set name or null if no such limit is requested
414      * @param metadataPrefix
415      * the OAI metadataPrefix or null if no such limit is requested
416      * @return a Map object containing entries for a "records" Iterator object
417      * (containing XML <record/>Strings) and an optional
418      * "resumptionMap" Map.
419      * @exception OAIInternalServerError
420      * signals an http status code 500 problem
421      * @exception NoSetHierarchyException
422      * The repository doesn't support sets.
423      * @exception CannotDisseminateFormatException
424      * the metadataPrefix isn't supported by the item.
425      */

426     public Map JavaDoc listRecords(String JavaDoc from, String JavaDoc until, String JavaDoc set,
427             String JavaDoc metadataPrefix) throws OAIInternalServerError,
428             NoSetHierarchyException, CannotDisseminateFormatException,
429             NoItemsMatchException, BadArgumentException
430     {
431         log
432                 .info(LogManager.getHeader(null, "oai_request",
433                         "verb=listRecords,from="
434                                 + ((from == null) ? "null" : from)
435                                 + ",until="
436                                 + ((until == null) ? "null" : until)
437                                 + ",set="
438                                 + ((set == null) ? "null" : set)
439                                 + ",metadataPrefix="
440                                 + ((metadataPrefix == null) ? "null"
441                                         : metadataPrefix)));
442
443         Map JavaDoc m = doRecordHarvest(from, until, set, metadataPrefix, 0);
444
445         // Null means bad metadata prefix was bad
446
if (m == null)
447         {
448             log.info(LogManager.getHeader(null, "oai_error",
449                     "cannot_disseminate_format"));
450             throw new CannotDisseminateFormatException(metadataPrefix);
451         }
452
453         // If there were zero results, return the appropriate error
454
Iterator JavaDoc i = (Iterator JavaDoc) m.get("records");
455
456         if ((i == null) || !i.hasNext())
457         {
458             log.info(LogManager.getHeader(null, "oai_error", "no_items_match"));
459             throw new NoItemsMatchException();
460         }
461
462         return m;
463     }
464
465     /**
466      * Retrieve the next set of records associated with the resumptionToken
467      *
468      * @param resumptionToken
469      * implementation-dependent format taken from the previous
470      * listRecords() Map result.
471      * @return a Map object containing entries for "headers" and "identifiers"
472      * Iterators (both containing Strings) as well as an optional
473      * "resumptionMap" Map.
474      * @exception OAIInternalServerError
475      * signals an http status code 500 problem
476      * @exception BadResumptionTokenException
477      * the value of the resumptionToken argument is invalid or
478      * expired.
479      */

480     public Map JavaDoc listRecords(String JavaDoc resumptionToken)
481             throws BadResumptionTokenException, OAIInternalServerError
482     {
483         log.info(LogManager.getHeader(null, "oai_request",
484                 "verb=listRecords,resumptionToken=" + resumptionToken));
485
486         /*
487          * FIXME: This may return zero records if the previous harvest returned
488          * a number of records that's an exact multiple of MAX_RECORDS. I hope
489          * that's OK.
490          */

491         Object JavaDoc[] params = decodeResumptionToken(resumptionToken);
492         Integer JavaDoc offset = (Integer JavaDoc) params[4];
493
494         Map JavaDoc m = null;
495
496         /*
497          * We catch BadArgumentExceptions here, because doRecordHarvest() throws
498          * BadArgumentExcpetions when the set spec is bad. set spec bad == bad
499          * resumption token.
500          */

501         try
502         {
503             m = doRecordHarvest((String JavaDoc) params[0], (String JavaDoc) params[1],
504                     (String JavaDoc) params[2], (String JavaDoc) params[3], offset.intValue());
505         }
506         catch (BadArgumentException bae)
507         {
508             m = null;
509         }
510
511         // null result means a problem -> bad resumption token
512
if (m == null)
513         {
514             log.info(LogManager.getHeader(null, "oai_error",
515                     "bad_resumption_token"));
516             throw new BadResumptionTokenException();
517         }
518
519         return m;
520     }
521
522     /**
523      * Method to do the actual harvest of records
524      *
525      * @param from
526      * OAI 'from' parameter
527      * @param until
528      * OAI 'until' parameter
529      * @param set
530      * OAI 'set' parameter
531      * @param metadataPrefix
532      * OAI 'metadataPrefix' parameter
533      * @param offset
534      * where to start this harvest
535      *
536      * @return the Map for listRecords to return, or null if the metadataPrefix
537      * is invalid
538      */

539     private Map JavaDoc doRecordHarvest(String JavaDoc from, String JavaDoc until, String JavaDoc set,
540             String JavaDoc metadataPrefix, int offset) throws OAIInternalServerError,
541             BadArgumentException
542     {
543         Context context = null;
544         String JavaDoc schemaURL = getCrosswalks().getSchemaURL(metadataPrefix);
545         Map JavaDoc results = new HashMap JavaDoc();
546
547         if (schemaURL == null)
548         {
549             return null;
550         }
551
552         // List to put results in
553
List JavaDoc records = new LinkedList JavaDoc();
554
555         try
556         {
557             context = new Context();
558
559             // Get the relevant HarvestedItemInfo objects to make headers
560
Collection scope = resolveSet(context, set);
561             List JavaDoc itemInfos = Harvest.harvest(context, scope, from, until,
562                     offset, MAX_RECORDS, // Limit amount returned from one
563
// request
564
true, true, true); // Need items, containers + withdrawals
565

566             // Build list of XML records from item info objects
567
Iterator JavaDoc i = itemInfos.iterator();
568
569             while (i.hasNext())
570             {
571                 HarvestedItemInfo itemInfo = (HarvestedItemInfo) i.next();
572
573                 try
574                 {
575                     String JavaDoc recordXML = getRecordFactory().create(itemInfo,
576                             schemaURL, metadataPrefix);
577                     records.add(recordXML);
578                 }
579                 catch (CannotDisseminateFormatException cdfe)
580                 {
581                     /*
582                      * FIXME: I've a feeling a
583                      * "CannotDisseminateFormatException" should be discarded
584                      * here - it's OK if some records in the requested date
585                      * range don't have the requested metadata format available.
586                      * I'll just log it for now.
587                      */

588                     if (log.isDebugEnabled())
589                     {
590                         log.debug(LogManager.getHeader(context, "oai_warning",
591                                 "Couldn't disseminate " + metadataPrefix
592                                         + " for " + itemInfo.handle));
593                     }
594                 }
595             }
596
597             // Put results in form needed to return
598
results.put("records", records.iterator());
599
600             log.info(LogManager.getHeader(context, "oai_harvest", "results="
601                     + records.size()));
602
603             // If we have MAX_RECORDS records, we need to provide a resumption
604
// token
605
if (records.size() >= MAX_RECORDS)
606             {
607                 String JavaDoc resumptionToken = makeResumptionToken(from, until, set,
608                         metadataPrefix, offset + MAX_RECORDS);
609
610                 if (log.isDebugEnabled())
611                 {
612                     log.debug(LogManager
613                             .getHeader(context, "made_resumption_token",
614                                     "token=" + resumptionToken));
615                 }
616
617                 results.put("resumptionMap", getResumptionMap(resumptionToken));
618
619                 //results.put("resumptionToken", resumptionToken);
620
}
621         }
622         catch (SQLException JavaDoc se)
623         {
624             // Log the error
625
log.warn(LogManager.getHeader(context, "database_error", ""), se);
626
627             throw new OAIInternalServerError(se.toString());
628         }
629         catch (ParseException JavaDoc pe)
630         {
631             throw new OAIInternalServerError(pe.toString());
632         }
633         finally
634         {
635             if (context != null)
636             {
637                 context.abort();
638             }
639         }
640
641         return results;
642     }
643
644     /**
645      * Retrieve a list of sets that satisfy the specified criteria
646      *
647      * @return a Map object containing "sets" Iterator object (contains
648      * <setSpec/>XML Strings) as well as an optional resumptionMap Map.
649      * @exception OAIBadRequestException
650      * signals an http status code 400 problem
651      * @exception OAIInternalServerError
652      * signals an http status code 500 problem
653      */

654     public Map JavaDoc listSets() throws NoSetHierarchyException,
655             OAIInternalServerError
656     {
657         log.info(LogManager.getHeader(null, "oai_request", "verb=listSets"));
658
659         Context context = null;
660
661         // List to put results in
662
List JavaDoc sets = new LinkedList JavaDoc();
663
664         try
665         {
666             context = new Context();
667
668             Collection[] allCols = Collection.findAll(context);
669             StringBuffer JavaDoc spec = null;
670             for (int i = 0; i < allCols.length; i++)
671             {
672                 spec = new StringBuffer JavaDoc("<set><setSpec>hdl_");
673                 spec.append(allCols[i].getHandle().replace('/', '_'));
674                 spec.append("</setSpec>");
675                 String JavaDoc collName = allCols[i].getMetadata("name");
676                 if(collName != null)
677                 {
678                     spec.append("<setName>");
679                     spec.append(Utils.addEntities(collName));
680                     spec.append("</setName>");
681                 }
682                 else
683                 {
684                     spec.append("<setName />");
685                     // Warn that there is an error of a null set name
686
log.info(LogManager.getHeader(null, "oai_error",
687                                    "null_set_name_for_set_id_" + allCols[i].getHandle()));
688                 }
689                 spec.append("</set>");
690                 sets.add(spec.toString());
691             }
692         }
693         catch (SQLException JavaDoc se)
694         {
695             // Log the error
696
log.warn(LogManager.getHeader(context, "database_error", ""), se);
697
698             throw new OAIInternalServerError(se.toString());
699         }
700         finally
701         {
702             if (context != null)
703             {
704                 context.abort();
705             }
706         }
707
708         // Put results in form needed to return
709
Map JavaDoc results = new HashMap JavaDoc();
710         results.put("sets", sets.iterator());
711
712         return results;
713     }
714
715     /**
716      * Retrieve the next set of sets associated with the resumptionToken
717      *
718      * @param resumptionToken
719      * implementation-dependent format taken from the previous
720      * listSets() Map result.
721      * @return a Map object containing "sets" Iterator object (contains
722      * <setSpec/>XML Strings) as well as an optional resumptionMap Map.
723      * @exception BadResumptionTokenException
724      * the value of the resumptionToken is invalid or expired.
725      * @exception OAIInternalServerError
726      * signals an http status code 500 problem
727      */

728     public Map JavaDoc listSets(String JavaDoc resumptionToken)
729             throws BadResumptionTokenException, OAIInternalServerError
730     {
731         // Resumption tokens not yet supported
732
throw new BadResumptionTokenException();
733     }
734
735     /**
736      * close the repository
737      */

738     public void close()
739     {
740     }
741
742     // ******************************************
743
// Internal DSpace utility methods below here
744
// ******************************************
745

746     /**
747      * Get the community or collection signified by a set spec
748      *
749      * @param context
750      * DSpace context object
751      * @param set
752      * OAI set spec
753      * @return the corresponding community or collection, or null if no set
754      * provided
755      */

756     private Collection resolveSet(Context context, String JavaDoc set)
757             throws SQLException JavaDoc, BadArgumentException
758     {
759         if (set == null)
760         {
761             return null;
762         }
763
764         DSpaceObject o = null;
765
766         /*
767          * set specs are in form hdl_123.456_789 corresponding to
768          * hdl:123.456/789
769          */

770         if (set.startsWith("hdl_"))
771         {
772             // Looks OK so far... turn second _ into /
773
String JavaDoc handle = set.substring(4).replace('_', '/');
774             o = HandleManager.resolveToObject(context, handle);
775         }
776
777         // If it corresponds to a collection, that's the set we want
778
if ((o != null) && o instanceof Collection)
779         {
780             return (Collection) o;
781         }
782
783         // Handle is either non-existent, or corresponds to a non-collection
784
// Either way, a bad set spec, ergo a bad argument
785
throw new BadArgumentException();
786     }
787
788     /**
789      * Create a resumption token. The relevant parameters for the harvest are
790      * put in a
791      *
792      * @param from
793      * OAI 'from' parameter
794      * @param until
795      * OAI 'until' parameter
796      * @param set
797      * OAI 'set' parameter
798      * @param prefix
799      * OAI 'metadataPrefix' parameter
800      * @param offset
801      * where to start the next harvest
802      *
803      * @return the appropriate resumption token
804      */

805     private String JavaDoc makeResumptionToken(String JavaDoc from, String JavaDoc until, String JavaDoc set,
806             String JavaDoc prefix, int offset)
807     {
808         StringBuffer JavaDoc token = new StringBuffer JavaDoc();
809
810         if (from != null)
811         {
812             token.append(from);
813         }
814
815         token.append("/");
816
817         if (until != null)
818         {
819             token.append(until);
820         }
821
822         token.append("/");
823
824         if (set != null)
825         {
826             token.append(set);
827         }
828
829         token.append("/");
830
831         if (prefix != null)
832         {
833             token.append(prefix);
834         }
835
836         token.append("/");
837         token.append(String.valueOf(offset));
838
839         return (token.toString());
840     }
841
842     /**
843      * Get the information out of a resumption token
844      *
845      * @param token
846      * the resumption token
847      * @return a 5-long array of Objects; 4 Strings (from, until, set, prefix)
848      * and an Integer (the offset)
849      */

850     private Object JavaDoc[] decodeResumptionToken(String JavaDoc token)
851             throws BadResumptionTokenException
852     {
853         Object JavaDoc[] obj = new Object JavaDoc[5];
854         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(token, "/", true);
855
856         try
857         {
858             // Extract from, until, set, prefix
859
for (int i = 0; i < 4; i++)
860             {
861                 if (!st.hasMoreTokens())
862                 {
863                     throw new BadResumptionTokenException();
864                 }
865
866                 String JavaDoc s = st.nextToken();
867
868                 // If this value is a delimiter /, we have no value for this
869
// part
870
// of the resumption token.
871
if (s.equals("/"))
872                 {
873                     obj[i] = null;
874                 }
875                 else
876                 {
877                     obj[i] = s;
878
879                     // Skip the delimiter
880
st.nextToken();
881                 }
882
883                 log.debug("is: " + (String JavaDoc) obj[i]);
884             }
885
886             if (!st.hasMoreTokens())
887             {
888                 throw new BadResumptionTokenException();
889             }
890
891             obj[4] = new Integer JavaDoc(st.nextToken());
892         }
893         catch (NumberFormatException JavaDoc nfe)
894         {
895             throw new BadResumptionTokenException();
896         }
897         catch (NoSuchElementException JavaDoc nsee)
898         {
899             throw new BadResumptionTokenException();
900         }
901
902         return obj;
903     }
904 }
905
Popular Tags