/** * The contents of this file are subject to the license and copyright * detailed in the LICENSE and NOTICE files at the root of the source * tree and available online at * * http://www.dspace.org/license/ */ package org.dspace.sword; import java.io.File; import java.sql.SQLException; import java.util.Date; import java.util.StringTokenizer; import org.apache.log4j.Logger; import org.dspace.content.*; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.packager.PackageIngester; import org.dspace.content.packager.PackageParameters; import org.dspace.content.service.ItemService; import org.dspace.core.ConfigurationManager; import org.dspace.core.Context; import org.dspace.core.factory.CoreServiceFactory; import org.dspace.handle.factory.HandleServiceFactory; import org.dspace.handle.service.HandleService; import org.purl.sword.base.Deposit; import org.purl.sword.base.SWORDErrorException; public class SWORDMETSIngester implements SWORDIngester { private SWORDService swordService; protected ItemService itemService = ContentServiceFactory.getInstance() .getItemService(); /** Log4j logger */ public static final Logger log = Logger.getLogger(SWORDMETSIngester.class); /* (non-Javadoc) * @see org.dspace.sword.SWORDIngester#ingest(org.dspace.core.Context, org.purl.sword.base.Deposit) */ public DepositResult ingest(SWORDService service, Deposit deposit, DSpaceObject dso) throws DSpaceSWORDException, SWORDErrorException { try { // first, make sure this is the right kind of ingester, and set the collection if (!(dso instanceof Collection)) { throw new DSpaceSWORDException( "Tried to run an ingester on wrong target type"); } Collection collection = (Collection) dso; // now set the sword service swordService = service; // get the things out of the service that we need Context context = swordService.getContext(); // get deposited file as InputStream File depositFile = deposit.getFile(); // load the plugin manager for the required configuration String cfg = ConfigurationManager.getProperty("sword-server", "mets-ingester.package-ingester"); if (cfg == null || "".equals(cfg)) { cfg = "METS"; // default to METS } swordService.message("Using package manifest format: " + cfg); PackageIngester pi = (PackageIngester) CoreServiceFactory.getInstance().getPluginService() .getNamedPlugin(PackageIngester.class, cfg); swordService.message( "Loaded package ingester: " + pi.getClass().getName()); // the licence is either in the zip or the mets manifest. Either way // it's none of our business here String licence = null; // Initialize parameters to packager PackageParameters params = new PackageParameters(); // Force package ingester to respect Collection workflows params.setWorkflowEnabled(true); // Should restore mode be enabled, i.e. keep existing handle? if (ConfigurationManager .getBooleanProperty("sword-server", "restore-mode.enable", false)) { params.setRestoreModeEnabled(true); } // Whether or not to use the collection template params.setUseCollectionTemplate(ConfigurationManager .getBooleanProperty( "mets.default.ingest.useCollectionTemplate", false)); // ingest the item from the temp file DSpaceObject ingestedObject = pi .ingest(context, collection, depositFile, params, licence); if (ingestedObject == null) { swordService.message( "Failed to ingest the package; throwing exception"); throw new SWORDErrorException( DSpaceSWORDErrorCodes.UNPACKAGE_FAIL, "METS package ingester failed to unpack package"); } //Verify we have an Item as a result -- SWORD can only ingest Items if (!(ingestedObject instanceof Item)) { throw new DSpaceSWORDException( "DSpace Ingester returned wrong object type -- not an Item result."); } else { //otherwise, we have an item, and a workflow should have already been started for it. swordService.message("Workflow process started"); } // get reference to item so that we can report on it Item installedItem = (Item) ingestedObject; // update the item metadata to inclue the current time as // the updated date this.setUpdatedDate(context, installedItem); // DSpace ignores the slug value as suggested identifier, but // it does store it in the metadata this.setSlug(installedItem, deposit.getSlug()); // in order to write these changes, we need to bypass the // authorisation briefly, because although the user may be // able to add stuff to the repository, they may not have // WRITE permissions on the archive. context.turnOffAuthorisationSystem(); itemService.update(context, installedItem); context.restoreAuthSystemState(); // for some reason, DSpace will not give you the handle automatically, // so we have to look it up HandleService handleService = HandleServiceFactory.getInstance() .getHandleService(); String handle = handleService.findHandle(context, installedItem); swordService.message("Ingest successful"); swordService.message("Item created with internal identifier: " + installedItem.getID()); if (handle != null) { swordService.message( "Item created with external identifier: " + handle); } else { swordService.message( "No external identifier available at this stage (item in workflow)"); } DepositResult dr = new DepositResult(); dr.setItem(installedItem); dr.setHandle(handle); dr.setTreatment(this.getTreatment()); return dr; } catch (RuntimeException re) { log.error("caught exception: ", re); throw re; } catch (Exception e) { log.error("caught exception: ", e); throw new DSpaceSWORDException(e); } } /** * Add the current date to the item metadata. This looks up * the field in which to store this metadata in the configuration * sword.updated.field * * * @param context * @param item * @throws DSpaceSWORDException */ private void setUpdatedDate(Context context, Item item) throws DSpaceSWORDException { String field = ConfigurationManager .getProperty("sword-server", "updated.field"); if (field == null || "".equals(field)) { throw new DSpaceSWORDException( "No configuration, or configuration is invalid for: sword.updated.field"); } MetadataFieldInfo dc = this.configToDC(field, null); try { itemService.clearMetadata(context, item, dc.schema, dc.element, dc.qualifier, Item.ANY); DCDate date = new DCDate(new Date()); itemService.addMetadata(context, item, dc.schema, dc.element, dc.qualifier, null, date.toString()); } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } swordService.message( "Updated date added to response from item metadata where available"); } /** * Store the given slug value (which is used for suggested identifiers, * and which DSpace ignores) in the item metadata. This looks up the * field in which to store this metadata in the configuration * sword.slug.field * * @param item * @param slugVal * @throws DSpaceSWORDException */ private void setSlug(Item item, String slugVal) throws DSpaceSWORDException { // if there isn't a slug value, don't set it if (slugVal == null) { return; } String field = ConfigurationManager .getProperty("sword-server", "slug.field"); if (field == null || "".equals(field)) { throw new DSpaceSWORDException( "No configuration, or configuration is invalid for: sword.slug.field"); } MetadataFieldInfo mfi = this.configToDC(field, null); try { itemService .clearMetadata(swordService.getContext(), item, mfi.schema, mfi.element, mfi.qualifier, Item.ANY); itemService.addMetadata(swordService.getContext(), item, mfi.schema, mfi.element, mfi.qualifier, null, slugVal); } catch (SQLException e) { log.error("Caught exception: ", e); throw new DSpaceSWORDException(e); } swordService.message("Slug value set in response where available"); } /** * utility method to turn given metadata fields of the form schema.element.qualifier into Metadatum objects which can be used to access metadata in items. * * The def parameter should be null, * or "" depending on how you intend to use the Metadatum object * * @param config * @param def * @return */ private MetadataFieldInfo configToDC(String config, String def) { MetadataFieldInfo mfi = new MetadataFieldInfo(); mfi.schema = def; mfi.element = def; mfi.qualifier = def; StringTokenizer stz = new StringTokenizer(config, "."); mfi.schema = stz.nextToken(); mfi.element = stz.nextToken(); if (stz.hasMoreTokens()) { mfi.qualifier = stz.nextToken(); } return mfi; } /** * The human readable description of the treatment this ingester has * put the deposit through * * @return * @throws DSpaceSWORDException */ private String getTreatment() throws DSpaceSWORDException { return "The package has been deposited into DSpace. Each file has been unpacked " + "and provided with a unique identifier. The metadata in the manifest has been " + "extracted and attached to the DSpace item, which has been provided with " + "an identifier leading to an HTML splash page."; } private class MetadataFieldInfo { private String schema; private String element; private String qualifier; } }