1 40 package org.dspace.app.oai; 41 42 import java.sql.SQLException ; 43 import java.text.ParseException ; 44 import java.util.HashMap ; 45 import java.util.Iterator ; 46 import java.util.LinkedList ; 47 import java.util.List ; 48 import java.util.Map ; 49 import java.util.NoSuchElementException ; 50 import java.util.Properties ; 51 import java.util.StringTokenizer ; 52 import java.util.Vector ; 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 85 public class DSpaceOAICatalog extends AbstractCatalog 86 { 87 88 private static Logger log = Logger.getLogger(DSpaceOAICatalog.class); 89 90 91 public final static String OAI_ID_PREFIX = "oai:" 92 + ConfigurationManager.getProperty("dspace.hostname") + ":"; 93 94 95 private final int MAX_RECORDS = 100; 96 97 public DSpaceOAICatalog(Properties properties) 98 { 99 } 101 102 118 public Vector getSchemaLocations(String 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 try 131 { 132 context = new Context(); 133 134 if (identifier.startsWith(OAI_ID_PREFIX)) 136 { 137 itemInfo = Harvest.getSingle(context, identifier 138 .substring(OAI_ID_PREFIX.length()), false); 141 } 142 } 143 catch (SQLException se) 144 { 145 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 208 public Map listIdentifiers(String from, String until, String set, 209 String 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 Context context = null; 227 228 List headers = new LinkedList (); 230 List identifiers = new LinkedList (); 231 232 try 233 { 234 context = new Context(); 235 236 Collection scope = resolveSet(context, set); 238 List itemInfos = Harvest.harvest(context, scope, from, until, 0, 0, false, true, true); 242 243 if (itemInfos.size() == 0) 246 { 247 log.info(LogManager.getHeader(null, "oai_error", 248 "no_items_match")); 249 throw new NoItemsMatchException(); 250 } 251 252 Iterator i = itemInfos.iterator(); 254 255 while (i.hasNext()) 256 { 257 HarvestedItemInfo itemInfo = (HarvestedItemInfo) i.next(); 258 259 String [] header = getRecordFactory().createHeader(itemInfo); 260 261 headers.add(header[0]); 262 identifiers.add(header[1]); 263 } 264 } 265 catch (SQLException se) 266 { 267 log.warn(LogManager.getHeader(context, "database_error", ""), se); 269 270 throw new OAIInternalServerError(se.toString()); 271 } 272 catch (ParseException pe) 273 { 274 throw new OAIInternalServerError(pe.toString()); 275 } 276 finally 277 { 278 if (context != null) 279 { 280 context.abort(); 281 } 282 } 283 284 Map results = new HashMap (); 286 results.put("headers", headers.iterator()); 287 results.put("identifiers", identifiers.iterator()); 288 289 return results; 290 } 291 292 306 public Map listIdentifiers(String resumptionToken) 307 throws BadResumptionTokenException, OAIInternalServerError 308 { 309 throw new BadResumptionTokenException(); 311 } 312 313 328 public String getRecord(String identifier, String 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 record = null; 342 HarvestedItemInfo itemInfo = null; 343 344 try 346 { 347 if (identifier.startsWith(OAI_ID_PREFIX)) 349 { 350 context = new Context(); 351 352 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 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 se) 380 { 381 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 426 public Map listRecords(String from, String until, String set, 427 String 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 m = doRecordHarvest(from, until, set, metadataPrefix, 0); 444 445 if (m == null) 447 { 448 log.info(LogManager.getHeader(null, "oai_error", 449 "cannot_disseminate_format")); 450 throw new CannotDisseminateFormatException(metadataPrefix); 451 } 452 453 Iterator i = (Iterator ) 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 480 public Map listRecords(String resumptionToken) 481 throws BadResumptionTokenException, OAIInternalServerError 482 { 483 log.info(LogManager.getHeader(null, "oai_request", 484 "verb=listRecords,resumptionToken=" + resumptionToken)); 485 486 491 Object [] params = decodeResumptionToken(resumptionToken); 492 Integer offset = (Integer ) params[4]; 493 494 Map m = null; 495 496 501 try 502 { 503 m = doRecordHarvest((String ) params[0], (String ) params[1], 504 (String ) params[2], (String ) params[3], offset.intValue()); 505 } 506 catch (BadArgumentException bae) 507 { 508 m = null; 509 } 510 511 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 539 private Map doRecordHarvest(String from, String until, String set, 540 String metadataPrefix, int offset) throws OAIInternalServerError, 541 BadArgumentException 542 { 543 Context context = null; 544 String schemaURL = getCrosswalks().getSchemaURL(metadataPrefix); 545 Map results = new HashMap (); 546 547 if (schemaURL == null) 548 { 549 return null; 550 } 551 552 List records = new LinkedList (); 554 555 try 556 { 557 context = new Context(); 558 559 Collection scope = resolveSet(context, set); 561 List itemInfos = Harvest.harvest(context, scope, from, until, 562 offset, MAX_RECORDS, true, true, true); 566 Iterator i = itemInfos.iterator(); 568 569 while (i.hasNext()) 570 { 571 HarvestedItemInfo itemInfo = (HarvestedItemInfo) i.next(); 572 573 try 574 { 575 String recordXML = getRecordFactory().create(itemInfo, 576 schemaURL, metadataPrefix); 577 records.add(recordXML); 578 } 579 catch (CannotDisseminateFormatException cdfe) 580 { 581 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 results.put("records", records.iterator()); 599 600 log.info(LogManager.getHeader(context, "oai_harvest", "results=" 601 + records.size())); 602 603 if (records.size() >= MAX_RECORDS) 606 { 607 String 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 } 621 } 622 catch (SQLException se) 623 { 624 log.warn(LogManager.getHeader(context, "database_error", ""), se); 626 627 throw new OAIInternalServerError(se.toString()); 628 } 629 catch (ParseException 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 654 public Map listSets() throws NoSetHierarchyException, 655 OAIInternalServerError 656 { 657 log.info(LogManager.getHeader(null, "oai_request", "verb=listSets")); 658 659 Context context = null; 660 661 List sets = new LinkedList (); 663 664 try 665 { 666 context = new Context(); 667 668 Collection[] allCols = Collection.findAll(context); 669 StringBuffer spec = null; 670 for (int i = 0; i < allCols.length; i++) 671 { 672 spec = new StringBuffer ("<set><setSpec>hdl_"); 673 spec.append(allCols[i].getHandle().replace('/', '_')); 674 spec.append("</setSpec>"); 675 String 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 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 se) 694 { 695 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 Map results = new HashMap (); 710 results.put("sets", sets.iterator()); 711 712 return results; 713 } 714 715 728 public Map listSets(String resumptionToken) 729 throws BadResumptionTokenException, OAIInternalServerError 730 { 731 throw new BadResumptionTokenException(); 733 } 734 735 738 public void close() 739 { 740 } 741 742 746 756 private Collection resolveSet(Context context, String set) 757 throws SQLException , BadArgumentException 758 { 759 if (set == null) 760 { 761 return null; 762 } 763 764 DSpaceObject o = null; 765 766 770 if (set.startsWith("hdl_")) 771 { 772 String handle = set.substring(4).replace('_', '/'); 774 o = HandleManager.resolveToObject(context, handle); 775 } 776 777 if ((o != null) && o instanceof Collection) 779 { 780 return (Collection) o; 781 } 782 783 throw new BadArgumentException(); 786 } 787 788 805 private String makeResumptionToken(String from, String until, String set, 806 String prefix, int offset) 807 { 808 StringBuffer token = new StringBuffer (); 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 850 private Object [] decodeResumptionToken(String token) 851 throws BadResumptionTokenException 852 { 853 Object [] obj = new Object [5]; 854 StringTokenizer st = new StringTokenizer (token, "/", true); 855 856 try 857 { 858 for (int i = 0; i < 4; i++) 860 { 861 if (!st.hasMoreTokens()) 862 { 863 throw new BadResumptionTokenException(); 864 } 865 866 String s = st.nextToken(); 867 868 if (s.equals("/")) 872 { 873 obj[i] = null; 874 } 875 else 876 { 877 obj[i] = s; 878 879 st.nextToken(); 881 } 882 883 log.debug("is: " + (String ) obj[i]); 884 } 885 886 if (!st.hasMoreTokens()) 887 { 888 throw new BadResumptionTokenException(); 889 } 890 891 obj[4] = new Integer (st.nextToken()); 892 } 893 catch (NumberFormatException nfe) 894 { 895 throw new BadResumptionTokenException(); 896 } 897 catch (NoSuchElementException nsee) 898 { 899 throw new BadResumptionTokenException(); 900 } 901 902 return obj; 903 } 904 } 905 | Popular Tags |