Example #1
0
  // initialize - get plugins and MD field settings from config
  @Override
  public void afterPropertiesSet() throws Exception {
    if (terms_schema == null) {
      String terms = ConfigurationManager.getProperty("embargo.field.terms");
      String lift = ConfigurationManager.getProperty("embargo.field.lift");
      if (terms == null || lift == null) {
        throw new IllegalStateException(
            "Missing one or more of the required DSpace configuration properties for EmbargoManager, check your configuration file.");
      }
      terms_schema = getSchemaOf(terms);
      terms_element = getElementOf(terms);
      terms_qualifier = getQualifierOf(terms);
      lift_schema = getSchemaOf(lift);
      lift_element = getElementOf(lift);
      lift_qualifier = getQualifierOf(lift);

      setter = (EmbargoSetter) PluginManager.getSinglePlugin(EmbargoSetter.class);
      if (setter == null) {
        throw new IllegalStateException(
            "The EmbargoSetter plugin was not defined in DSpace configuration.");
      }
      lifter = (EmbargoLifter) PluginManager.getSinglePlugin(EmbargoLifter.class);
      if (lifter == null) {
        throw new IllegalStateException(
            "The EmbargoLifter plugin was not defined in DSpace configuration.");
      }
    }
  }
  /**
   * Generate an object which conforms to the SWORDIngester interface. This Factory method may use
   * the given DSpace context and the given SWORD Deposit request to decide on the most appropriate
   * implementation of the interface to return.
   *
   * <p>To configure how this method will respond, configure the package ingester for the
   * appropriate media types and defaults. See the sword configuration documentation for more
   * details.
   *
   * @param context
   * @param deposit
   * @return
   * @throws DSpaceSwordException
   */
  public static SwordContentIngester getContentInstance(
      Context context, Deposit deposit, DSpaceObject dso) throws DSpaceSwordException, SwordError {
    SwordContentIngester ingester = null;

    // first look to see if there's an intester for the content type
    ingester =
        (SwordContentIngester)
            PluginManager.getNamedPlugin(
                "swordv2-server", SwordContentIngester.class, deposit.getMimeType());
    if (ingester != null) {
      return ingester;
    }

    // if no ingester, then
    // look to see if there's an ingester for the package format
    ingester =
        (SwordContentIngester)
            PluginManager.getNamedPlugin(
                "swordv2-server", SwordContentIngester.class, deposit.getPackaging());
    if (ingester == null) {
      throw new SwordError(
          UriRegistry.ERROR_CONTENT, "No ingester configured for this package type");
    }
    return ingester;
  }
  // return name of derived file as if MediaFilter created it, or null
  private String makeDerivedFilename(String bundleName, String origName) {
    // get the MediaFilter that would create this bundle:
    String mfNames[] = PluginManager.getAllPluginNames(MediaFilter.class);

    for (int i = 0; i < mfNames.length; ++i) {
      MediaFilter mf = (MediaFilter) PluginManager.getNamedPlugin(MediaFilter.class, mfNames[i]);
      if (bundleName.equals(mf.getBundleName())) return mf.getFilteredName(origName);
    }
    return null;
  }
Example #4
0
  @Override
  public String createMetadata(Object nativeItem) throws CannotDisseminateFormatException {
    HarvestedItemInfo hii = (HarvestedItemInfo) nativeItem;

    try {
      // Get a reference to our DSpace METS DisseminationCrosswalk
      // (likely this is org.dspace.content.crosswalk.METSDisseminationCrosswalk)
      DisseminationCrosswalk xwalk =
          (DisseminationCrosswalk)
              PluginManager.getNamedPlugin(DisseminationCrosswalk.class, "METS");

      // if no crosswalk found, thrown an error
      if (xwalk == null)
        throw new CannotDisseminateFormatException(
            "DSpace cannot disseminate METS format, as no DisseminationCrosswalk is configured which supports 'METS'");

      if (xwalk.canDisseminate(hii.item)) {
        // disseminate the object to METS
        Element rootElement = xwalk.disseminateElement(hii.item);

        // Return XML results as a formatted String
        return outputter.outputString(rootElement);
      } else return null; // cannot disseminate this type of object
    } catch (Exception e) {
      log.error("OAI-PMH METSCrosswalk error", e);
      return null;
    }
  }
Example #5
0
  /**
   * GET implementation returns the contents of the Item as a package. The query arg "package" must
   * be specified.
   *
   * @throws SQLException the SQL exception
   * @throws AuthorizeException the authorize exception
   * @throws ServletException the servlet exception
   * @throws IOException Signals that an I/O exception has occurred.
   * @throws DAVStatusException the DAV status exception
   */
  @Override
  protected void get() throws SQLException, AuthorizeException, IOException, DAVStatusException {
    // Check for overall read permission on Item, because nothing else will
    AuthorizeManager.authorizeAction(this.context, this.item, Constants.READ);

    String packageType = this.request.getParameter("package");
    Bundle[] original = this.item.getBundles("ORIGINAL");
    int bsid;

    if (packageType == null) {
      packageType = "default";
    }
    PackageDisseminator dip =
        (PackageDisseminator) PluginManager.getNamedPlugin(PackageDisseminator.class, packageType);
    if (dip == null) {
      throw new DAVStatusException(
          HttpServletResponse.SC_BAD_REQUEST,
          "Cannot find a disseminate plugin for package=" + packageType);
    } else {
      try {
        PackageParameters pparams = PackageParameters.create(this.request);
        this.response.setContentType(dip.getMIMEType(pparams));
        dip.disseminate(this.context, this.item, pparams, this.response.getOutputStream());
      } catch (CrosswalkException pe) {
        throw new DAVStatusException(
            HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
            "Failed in crosswalk of metadata: " + pe.toString());
      } catch (PackageException pe) {
        pe.log(log);
        throw new DAVStatusException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, pe.toString());
      }
    }
  }
 public static SwordEntryIngester getEntryInstance(
     Context context, Deposit deposit, DSpaceObject dso) throws DSpaceSwordException, SwordError {
   SwordEntryIngester ingester =
       (SwordEntryIngester)
           PluginManager.getSinglePlugin("swordv2-server", SwordEntryIngester.class);
   if (ingester == null) {
     throw new SwordError(
         UriRegistry.ERROR_CONTENT, "No ingester configured for handling sword entry documents");
   }
   return ingester;
 }
  /** Retrieve the named delegate */
  private static OrderFormatDelegate getDelegate(String name) {
    if (name != null && name.length() > 0) {
      // Check the cached array of names to see if the delegate has been configured
      for (int idx = 0; idx < delegates.length; idx++) {
        if (delegates[idx].equals(name)) {
          return (OrderFormatDelegate)
              PluginManager.getNamedPlugin(OrderFormatDelegate.class, name);
        }
      }
    }

    return null;
  }
 private void preProcessCommunityHome(
     Context context,
     HttpServletRequest request,
     HttpServletResponse response,
     Community community)
     throws ServletException, IOException, SQLException {
   try {
     CommunityHomeProcessor[] chp =
         (CommunityHomeProcessor[]) PluginManager.getPluginSequence(CommunityHomeProcessor.class);
     for (int i = 0; i < chp.length; i++) {
       chp[i].process(context, request, response, community);
     }
   } catch (Exception e) {
     log.error("caught exception: ", e);
     throw new ServletException(e);
   }
 }
  public Element disseminateElement(DSpaceObject dso)
      throws CrosswalkException, IOException, SQLException, AuthorizeException {
    if (dso.getType() != Constants.ITEM) {
      throw new CrosswalkObjectNotSupported(
          "METSDisseminationCrosswalk can only crosswalk an Item.");
    }
    Item item = (Item) dso;

    PackageDisseminator dip =
        (PackageDisseminator)
            PluginManager.getNamedPlugin(PackageDisseminator.class, METS_PACKAGER_PLUGIN);
    if (dip == null) {
      throw new CrosswalkInternalException(
          "Cannot find a disseminate plugin for package=" + METS_PACKAGER_PLUGIN);
    }

    try {
      // Set the manifestOnly=true param so we just get METS document
      PackageParameters pparams = new PackageParameters();
      pparams.put("manifestOnly", "true");

      // Create a temporary file to disseminate into
      String tempDirectory = ConfigurationManager.getProperty("upload.temp.dir");
      File tempFile =
          File.createTempFile("METSDissemination" + item.hashCode(), null, new File(tempDirectory));
      tempFile.deleteOnExit();

      // Disseminate METS to temp file
      Context context = new Context();
      dip.disseminate(context, item, pparams, tempFile);

      try {
        SAXBuilder builder = new SAXBuilder();
        Document metsDocument = builder.build(tempFile);
        return metsDocument.getRootElement();
      } catch (JDOMException je) {
        throw new MetadataValidationException(
            "Error parsing METS (see wrapped error message for more details) ", je);
      }
    } catch (PackageException pe) {
      throw new CrosswalkInternalException(
          "Failed making METS manifest in packager (see wrapped error message for more details) ",
          pe);
    }
  }
  public static void main(String[] argv) throws Exception {
    // set headless for non-gui workstations
    System.setProperty("java.awt.headless", "true");

    // create an options object and populate it
    CommandLineParser parser = new PosixParser();

    Options options = new Options();

    options.addOption(
        "v", "verbose", false, "print all extracted text and other details to STDOUT");
    options.addOption("f", "force", false, "force all bitstreams to be processed");
    options.addOption(
        "n", "noindex", false, "do NOT update the search index after filtering bitstreams");
    options.addOption("i", "identifier", true, "ONLY process bitstreams belonging to identifier");
    options.addOption("m", "maximum", true, "process no more than maximum items");
    options.addOption("h", "help", false, "help");

    CommandLine line = parser.parse(options, argv);

    if (line.hasOption('h')) {
      HelpFormatter myhelp = new HelpFormatter();
      myhelp.printHelp("MediaFilter\n", options);

      System.exit(0);
    }

    if (line.hasOption('v')) {
      isVerbose = true;
    }

    if (line.hasOption('n')) {
      updateIndex = false;
    }

    if (line.hasOption('f')) {
      isForce = true;
    }

    if (line.hasOption('i')) {
      identifier = line.getOptionValue('i');
    }

    if (line.hasOption('m')) {
      max2Process = Integer.parseInt(line.getOptionValue('m'));
      if (max2Process <= 1) {
        System.out.println("Invalid maximum value '" + line.getOptionValue('m') + "' - ignoring");
        max2Process = Integer.MAX_VALUE;
      }
    }

    // set up filters
    filterClasses = (MediaFilter[]) PluginManager.getPluginSequence(MediaFilter.class);
    for (int i = 0; i < filterClasses.length; i++) {
      String filterName = filterClasses[i].getClass().getName();
      String formats = ConfigurationManager.getProperty("filter." + filterName + ".inputFormats");
      if (formats != null) {
        filterFormats.put(filterName, Arrays.asList(formats.split(",[\\s]*")));
      }
    }

    Context c = null;

    try {
      c = new Context();

      // have to be super-user to do the filtering
      c.setIgnoreAuthorization(true);

      // now apply the filters
      if (identifier == null) {
        applyFiltersAllItems(c);
      } else // restrict application scope to identifier
      {
        DSpaceObject dso = HandleManager.resolveToObject(c, identifier);
        if (dso == null) {
          throw new IllegalArgumentException(
              "Cannot resolve " + identifier + " to a DSpace object");
        }

        switch (dso.getType()) {
          case Constants.COMMUNITY:
            applyFiltersCommunity(c, (Community) dso);
            break;
          case Constants.COLLECTION:
            applyFiltersCollection(c, (Collection) dso);
            break;
          case Constants.ITEM:
            applyFiltersItem(c, (Item) dso);
            break;
        }
      }

      // update search index?
      if (updateIndex) {
        System.out.println("Updating search index:");
        DSIndexer.updateIndex(c);
      }

      c.complete();
      c = null;
    } finally {
      if (c != null) {
        c.abort();
      }
    }
  }
  /** Write out a METS manifest. Mostly lifted from Rob Tansley's METS exporter. */
  private void writeManifest(Context context, Item item, PackageParameters params, OutputStream out)
      throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException,
          IOException {
    try {
      // Create the METS file
      Mets mets = new Mets();

      // Top-level stuff
      mets.setID(gensym("mets"));
      mets.setOBJID("hdl:" + item.getHandle());
      mets.setLABEL("DSpace Item");
      mets.setPROFILE(getProfile());

      // MetsHdr
      MetsHdr metsHdr = new MetsHdr();
      metsHdr.setCREATEDATE(new Date()); // FIXME: CREATEDATE is now:
      // maybe should be item create
      // date?

      // Agent
      Agent agent = new Agent();
      agent.setROLE(Role.CUSTODIAN);
      agent.setTYPE(Type.ORGANIZATION);
      Name name = new Name();
      name.getContent().add(new PCData(ConfigurationManager.getProperty("dspace.name")));
      agent.getContent().add(name);
      metsHdr.getContent().add(agent);
      mets.getContent().add(metsHdr);

      // add DMD sections
      // Each type element MAY be either just a MODS-and-crosswalk name, OR
      // a combination "MODS-name:crosswalk-name" (e.g. "DC:qDC").
      String dmdTypes[] = getDmdTypes(params);

      // record of ID of each dmdsec to make DMDID in structmap.
      String dmdGroup = gensym("dmd_group");
      String dmdId[] = new String[dmdTypes.length];
      for (int i = 0; i < dmdTypes.length; ++i) {
        dmdId[i] = gensym("dmd");
        XmlData xmlData = new XmlData();
        String xwalkName, metsName;
        String parts[] = dmdTypes[i].split(":", 2);
        if (parts.length > 1) {
          metsName = parts[0];
          xwalkName = parts[1];
        } else xwalkName = metsName = dmdTypes[i];

        DisseminationCrosswalk xwalk =
            (DisseminationCrosswalk)
                PluginManager.getNamedPlugin(DisseminationCrosswalk.class, xwalkName);
        if (xwalk == null)
          throw new PackageValidationException("Cannot find " + dmdTypes[i] + " crosswalk plugin!");
        else crosswalkToMets(xwalk, item, xmlData);

        DmdSec dmdSec = new DmdSec();
        dmdSec.setID(dmdId[i]);
        dmdSec.setGROUPID(dmdGroup);
        MdWrap mdWrap = new MdWrap();
        setMdType(mdWrap, metsName);
        mdWrap.getContent().add(xmlData);
        dmdSec.getContent().add(mdWrap);
        mets.getContent().add(dmdSec);
      }

      // Only add license AMD section if there are any licenses.
      // Catch authorization failures accessing license bitstreams
      // only if we are skipping unauthorized bitstreams.
      String licenseID = null;
      try {
        AmdSec amdSec = new AmdSec();
        addRightsMd(context, item, amdSec);
        if (amdSec.getContent().size() > 0) {
          licenseID = gensym("license");
          amdSec.setID(licenseID);
          mets.getContent().add(amdSec);
        }
      } catch (AuthorizeException e) {
        String unauth = (params == null) ? null : params.getProperty("unauthorized");
        if (!(unauth != null && unauth.equalsIgnoreCase("skip"))) throw e;
        else log.warn("Skipping license metadata because of access failure: " + e.toString());
      }

      // FIXME: History data???? Nooooo!!!!

      // fileSec - all non-metadata bundles go into fileGrp,
      // and each bitstream therein into a file.
      // Create the bitstream-level techMd and div's for structmap
      // at the same time so we can connec the IDREFs to IDs.
      FileSec fileSec = new FileSec();

      String techMdType = getTechMdType(params);
      String parts[] = techMdType.split(":", 2);
      String xwalkName, metsName;
      if (parts.length > 1) {
        metsName = parts[0];
        xwalkName = parts[1];
      } else xwalkName = metsName = techMdType;

      DisseminationCrosswalk xwalk =
          (DisseminationCrosswalk)
              PluginManager.getNamedPlugin(DisseminationCrosswalk.class, xwalkName);
      if (xwalk == null)
        throw new PackageValidationException("Cannot find " + xwalkName + " crosswalk plugin!");

      // log the primary bitstream for structmap
      String primaryBitstreamFileID = null;

      // accumulate content DIV items to put in structMap later.
      List contentDivs = new ArrayList();

      // how to handle unauthorized bundle/bitstream:
      String unauth = (params == null) ? null : params.getProperty("unauthorized");

      Bundle[] bundles = item.getBundles();
      for (int i = 0; i < bundles.length; i++) {
        if (PackageUtils.isMetaInfoBundle(bundles[i])) continue;

        // unauthorized bundle?
        // NOTE: This must match the logic in disseminate()
        if (!AuthorizeManager.authorizeActionBoolean(context, bundles[i], Constants.READ)) {
          if (unauth != null && (unauth.equalsIgnoreCase("skip"))) continue;
          else
            throw new AuthorizeException(
                "Not authorized to read Bundle named \"" + bundles[i].getName() + "\"");
        }

        Bitstream[] bitstreams = bundles[i].getBitstreams();

        // Create a fileGrp
        FileGrp fileGrp = new FileGrp();

        // Bundle name for USE attribute
        String bName = bundles[i].getName();
        if ((bName != null) && !bName.equals("")) fileGrp.setUSE(bundleToFileGrp(bName));

        // watch for primary bitstream
        int primaryBitstreamID = -1;
        boolean isContentBundle = false;
        if ((bName != null) && bName.equals("ORIGINAL")) {
          isContentBundle = true;
          primaryBitstreamID = bundles[i].getPrimaryBitstreamID();
        }

        for (int bits = 0; bits < bitstreams.length; bits++) {
          // Check for authorization.  Handle unauthorized
          // bitstreams to match the logic in disseminate(),
          // i.e. "unauth=zero" means include a 0-length bitstream,
          // "unauth=skip" means to ignore it (and exclude from
          // manifest).
          boolean auth =
              AuthorizeManager.authorizeActionBoolean(context, bitstreams[bits], Constants.READ);
          if (!auth) {
            if (unauth != null && unauth.equalsIgnoreCase("skip")) continue;
            else if (!(unauth != null && unauth.equalsIgnoreCase("zero")))
              throw new AuthorizeException(
                  "Not authorized to read Bitstream, SID="
                      + String.valueOf(bitstreams[bits].getSequenceID()));
          }

          String sid = String.valueOf(bitstreams[bits].getSequenceID());

          edu.harvard.hul.ois.mets.File file = new edu.harvard.hul.ois.mets.File();

          String xmlIDstart = "bitstream_";
          String fileID = xmlIDstart + sid;

          file.setID(fileID);

          // log primary bitstream for later (structMap)
          if (bitstreams[bits].getID() == primaryBitstreamID) primaryBitstreamFileID = fileID;

          // if this is content, add to structmap too:
          if (isContentBundle) {
            Div div = new Div();
            div.setID(gensym("div"));
            div.setTYPE("DSpace Content Bitstream");
            Fptr fptr = new Fptr();
            fptr.setFILEID(fileID);
            div.getContent().add(fptr);
            contentDivs.add(div);
          }

          file.setSEQ(bitstreams[bits].getSequenceID());

          String groupID = "GROUP_" + xmlIDstart + sid;

          /*
           * If we're in THUMBNAIL or TEXT bundles, the bitstream is
           * extracted text or a thumbnail, so we use the name to work
           * out which bitstream to be in the same group as
           */
          if ((bundles[i].getName() != null)
              && (bundles[i].getName().equals("THUMBNAIL")
                  || bundles[i].getName().startsWith("TEXT"))) {
            // Try and find the original bitstream, and chuck the
            // derived bitstream in the same group
            Bitstream original = findOriginalBitstream(item, bitstreams[bits]);

            if (original != null) {
              groupID = "GROUP_" + xmlIDstart + original.getSequenceID();
            }
          }

          file.setGROUPID(groupID);
          file.setMIMETYPE(bitstreams[bits].getFormat().getMIMEType());

          // FIXME: CREATED: no date

          file.setSIZE(auth ? bitstreams[bits].getSize() : 0);

          // translate checksum and type to METS, if available.
          String csType = bitstreams[bits].getChecksumAlgorithm();
          String cs = bitstreams[bits].getChecksum();
          if (auth && cs != null && csType != null) {
            try {
              file.setCHECKSUMTYPE(Checksumtype.parse(csType));
              file.setCHECKSUM(cs);
            } catch (MetsException e) {
              log.warn("Cannot set bitstream checksum type=" + csType + " in METS.");
            }
          }

          // FLocat: filename is MD5 checksum
          FLocat flocat = new FLocat();
          flocat.setLOCTYPE(Loctype.URL);
          flocat.setXlinkHref(makeBitstreamName(bitstreams[bits]));

          // Make bitstream techMD metadata, add to file.
          String techID = "techMd_for_bitstream_" + bitstreams[bits].getSequenceID();
          AmdSec fAmdSec = new AmdSec();
          fAmdSec.setID(techID);
          TechMD techMd = new TechMD();
          techMd.setID(gensym("tech"));
          MdWrap mdWrap = new MdWrap();
          setMdType(mdWrap, metsName);
          XmlData xmlData = new XmlData();
          mdWrap.getContent().add(xmlData);
          techMd.getContent().add(mdWrap);
          fAmdSec.getContent().add(techMd);
          mets.getContent().add(fAmdSec);
          crosswalkToMets(xwalk, bitstreams[bits], xmlData);
          file.setADMID(techID);

          // Add FLocat to File, and File to FileGrp
          file.getContent().add(flocat);
          fileGrp.getContent().add(file);
        }

        // Add fileGrp to fileSec
        fileSec.getContent().add(fileGrp);
      }

      // Add fileSec to document
      mets.getContent().add(fileSec);

      // Create simple structMap: initial div represents the Item,
      // and user-visible content bitstreams are in its child divs.
      StringBuffer dmdIds = new StringBuffer();
      for (int i = 0; i < dmdId.length; ++i) dmdIds.append(" " + dmdId[i]);
      StructMap structMap = new StructMap();
      structMap.setID(gensym("struct"));
      structMap.setTYPE("LOGICAL");
      structMap.setLABEL("DSpace");
      Div div0 = new Div();
      div0.setID(gensym("div"));
      div0.setTYPE("DSpace Item");
      div0.setDMDID(dmdIds.substring(1));
      if (licenseID != null) div0.setADMID(licenseID);

      // if there is a primary bitstream, add FPTR to it.
      if (primaryBitstreamFileID != null) {
        Fptr fptr = new Fptr();
        fptr.setFILEID(primaryBitstreamFileID);
        div0.getContent().add(fptr);
      }

      // add DIV for each content bitstream
      div0.getContent().addAll(contentDivs);

      structMap.getContent().add(div0);

      // Does subclass have something to add to structMap?
      addStructMap(context, item, params, mets);

      mets.getContent().add(structMap);

      mets.validate(new MetsValidator());

      mets.write(new MetsWriter(out));
    } catch (MetsException e) {
      // We don't pass up a MetsException, so callers don't need to
      // know the details of the METS toolkit
      // e.printStackTrace();
      throw new PackageValidationException(e);
    }
  }
Example #12
0
  public static void main(String[] argv) throws Exception {
    Options options = new Options();
    options.addOption("c", "collection", true, "destination collection(s) Handle (repeatable)");
    options.addOption("e", "eperson", true, "email address of eperson doing importing");
    options.addOption(
        "w",
        "install",
        false,
        "disable workflow; install immediately without going through collection's workflow");
    options.addOption("t", "type", true, "package type or MIMEtype");
    options.addOption(
        "o", "option", true, "Packager option to pass to plugin, \"name=value\" (repeatable)");
    options.addOption(
        "d", "disseminate", false, "Disseminate package (output); default is to submit.");
    options.addOption("i", "item", true, "Handle of item to disseminate.");
    options.addOption("h", "help", false, "help");

    CommandLineParser parser = new PosixParser();
    CommandLine line = parser.parse(options, argv);

    String sourceFile = null;
    String eperson = null;
    String[] collections = null;
    boolean useWorkflow = true;
    String packageType = null;
    boolean submit = true;
    String itemHandle = null;
    PackageParameters pkgParams = new PackageParameters();

    if (line.hasOption('h')) {
      HelpFormatter myhelp = new HelpFormatter();
      myhelp.printHelp("Packager  [options]  package-file|-\n", options);
      System.out.println("\nAvailable Submission Package (SIP) types:");
      String pn[] = PluginManager.getAllPluginNames(PackageIngester.class);
      for (int i = 0; i < pn.length; ++i) System.out.println("  " + pn[i]);
      System.out.println("\nAvailable Dissemination Package (DIP) types:");
      pn = PluginManager.getAllPluginNames(PackageDisseminator.class);
      for (int i = 0; i < pn.length; ++i) System.out.println("  " + pn[i]);
      System.exit(0);
    }
    if (line.hasOption('w')) useWorkflow = false;
    if (line.hasOption('e')) eperson = line.getOptionValue('e');
    if (line.hasOption('c')) collections = line.getOptionValues('c');
    if (line.hasOption('t')) packageType = line.getOptionValue('t');
    if (line.hasOption('i')) itemHandle = line.getOptionValue('i');
    String files[] = line.getArgs();
    if (files.length > 0) sourceFile = files[0];
    if (line.hasOption('d')) submit = false;
    if (line.hasOption('o')) {
      String popt[] = line.getOptionValues('o');
      for (int i = 0; i < popt.length; ++i) {
        String pair[] = popt[i].split("\\=", 2);
        if (pair.length == 2) pkgParams.addProperty(pair[0].trim(), pair[1].trim());
        else if (pair.length == 1) pkgParams.addProperty(pair[0].trim(), "");
        else System.err.println("Warning: Illegal package option format: \"" + popt[i] + "\"");
      }
    }

    // Sanity checks on arg list: required args
    if (sourceFile == null
        || eperson == null
        || packageType == null
        || (submit && collections == null)) {
      System.err.println("Error - missing a REQUIRED argument or option.\n");
      HelpFormatter myhelp = new HelpFormatter();
      myhelp.printHelp("PackageManager  [options]  package-file|-\n", options);
      System.exit(0);
    }

    // find the EPerson, assign to context
    Context context = new Context();
    EPerson myEPerson = null;
    myEPerson = EPerson.findByEmail(context, eperson);
    if (myEPerson == null) usageError("Error, eperson cannot be found: " + eperson);
    context.setCurrentUser(myEPerson);

    if (submit) {
      // make sure we have an input file

      // GWaller 11/1/10 Disable piping of input in - we need to archive the package so it is
      // simpler to assume a file stream
      //                 rather than save the System.in bytes and re-read.

      if (sourceFile.equals("-")) {
        usageError(
            "Error, input piping not allowed. Specify a file name of a physical file to read");
      }

      InputStream source = new FileInputStream(sourceFile);

      PackageIngester sip =
          (PackageIngester) PluginManager.getNamedPlugin(PackageIngester.class, packageType);
      if (sip == null) usageError("Error, Unknown package type: " + packageType);

      // find collections
      Collection[] mycollections = null;

      System.out.println("Destination collections:");

      // validate each collection arg to see if it's a real collection
      mycollections = new Collection[collections.length];
      for (int i = 0; i < collections.length; i++) {
        // sanity check: did handle resolve, and to a collection?
        DSpaceObject dso = HandleManager.resolveToObject(context, collections[i]);
        if (dso == null)
          throw new IllegalArgumentException(
              "Bad collection list -- "
                  + "Cannot resolve collection handle \""
                  + collections[i]
                  + "\"");
        else if (dso.getType() != Constants.COLLECTION)
          throw new IllegalArgumentException(
              "Bad collection list -- "
                  + "Object at handle \""
                  + collections[i]
                  + "\" is not a collection!");
        mycollections[i] = (Collection) dso;
        System.out.println(
            (i == 0 ? "  Owning " : "  ") + " Collection: " + mycollections[i].getMetadata("name"));
      }

      try {
        // GWaller 26/08/09 Support array of collections
        WorkspaceItem wi = sip.ingest(context, mycollections, source, pkgParams, null);

        // GWaller 11/1/10 IssueID #157 Archive the package
        InputStream sourceCopy = new FileInputStream(sourceFile);
        Bundle archivedBundle =
            BundleUtils.getBundleByName(wi.getItem(), Constants.ARCHIVED_CONTENT_PACKAGE_BUNDLE);
        Bitstream bs = archivedBundle.createBitstream(sourceCopy);
        bs.setName(new File(sourceFile).getName());
        bs.update();
        archivedBundle.update();

        if (useWorkflow) {
          String handle = null;

          // Check if workflow completes immediately, and
          // return Handle if so.
          WorkflowItem wfi = WorkflowManager.startWithoutNotify(context, wi);

          if (wfi.getState() == WorkflowManager.WFSTATE_ARCHIVE) {
            Item ni = wfi.getItem();
            handle = HandleManager.findHandle(context, ni);
          }
          if (handle == null)
            System.out.println("Created Workflow item, ID=" + String.valueOf(wfi.getID()));
          else System.out.println("Created and installed item, handle=" + handle);
        } else {
          InstallItem.installItem(context, wi);
          System.out.println(
              "Created and installed item, handle="
                  + HandleManager.findHandle(context, wi.getItem()));
        }
        context.complete();
        System.exit(0);
      } catch (Exception e) {
        // abort all operations
        context.abort();
        e.printStackTrace();
        System.out.println(e);
        System.exit(1);
      }
    } else {
      OutputStream dest =
          (sourceFile.equals("-"))
              ? (OutputStream) System.out
              : (OutputStream) (new FileOutputStream(sourceFile));

      PackageDisseminator dip =
          (PackageDisseminator)
              PluginManager.getNamedPlugin(PackageDisseminator.class, packageType);
      if (dip == null) usageError("Error, Unknown package type: " + packageType);

      DSpaceObject dso = HandleManager.resolveToObject(context, itemHandle);
      if (dso == null)
        throw new IllegalArgumentException(
            "Bad Item handle -- " + "Cannot resolve handle \"" + itemHandle);
      dip.disseminate(context, dso, pkgParams, dest);
    }
  }
  /**
   * PUT ingests a package as a new Item. Package type (must match pluggable packager name) is in
   * either (a) "package" query arg in URI (b) content-type request header
   *
   * @throws SQLException the SQL exception
   * @throws AuthorizeException the authorize exception
   * @throws ServletException the servlet exception
   * @throws IOException Signals that an I/O exception has occurred.
   * @throws DAVStatusException the DAV status exception
   */
  @Override
  protected void put()
      throws SQLException, AuthorizeException, ServletException, IOException, DAVStatusException {
    try {
      String packageType = this.request.getParameter("package");
      if (packageType == null) {
        packageType = this.request.getContentType();
      }
      if (packageType == null) {
        throw new DAVStatusException(
            HttpServletResponse.SC_BAD_REQUEST,
            "Cannot determine package type,  need content-type header or package param");
      }

      PackageIngester sip =
          (PackageIngester) PluginManager.getNamedPlugin(PackageIngester.class, packageType);
      if (sip == null) {
        throw new DAVStatusException(
            HttpServletResponse.SC_BAD_REQUEST,
            "Cannot find importer for package type: " + packageType);
      }

      /*
       * Ugh. Servlet container doesn't get end-of-file right on input
       * stream so we have to count it, when possible.
       */
      int contentLength = this.request.getIntHeader("Content-Length");
      InputStream pis = this.request.getInputStream();
      if (contentLength >= 0) {
        pis = new CountedInputStream(pis, contentLength);
        log.debug("put: Using CountedInputStream, length=" + String.valueOf(contentLength));
      }
      WorkspaceItem wi =
          sip.ingest(
              this.context, this.collection, pis, PackageParameters.create(this.request), null);
      WorkflowItem wfi = WorkflowManager.startWithoutNotify(this.context, wi);

      // get new item's location: if workflow completed, then look
      // for handle (but be ready for disappointment); otherwise,
      // return the workflow item's resource.
      int state = wfi.getState();
      String location = null;
      if (state == WorkflowManager.WFSTATE_ARCHIVE) {
        Item ni = wfi.getItem();

        // FIXME: I'm not sure this is what we want
        String handle = ni.getExternalIdentifier().getCanonicalForm();
        //                String handle = HandleManager.findHandle(this.context, ni);

        String end = (handle != null) ? DAVDSpaceObject.getPathElt(handle) : DAVItem.getPathElt(ni);
        DAVItem newItem =
            new DAVItem(this.context, this.request, this.response, makeChildPath(end), ni);
        location = newItem.hrefURL();
      } else if (state == WorkflowManager.WFSTATE_SUBMIT
          || state == WorkflowManager.WFSTATE_STEP1POOL) {
        location = hrefPrefix() + DAVWorkflow.getPath(wfi);
      } else {
        throw new DAVStatusException(
            HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
            "Workflow object in unexpected state, state="
                + String.valueOf(state)
                + ", aborting PUT.");
      }

      this.context.commit();
      log.info("Created new Item, location=" + location);
      this.response.setHeader("Location", location);
      this.response.setStatus(HttpServletResponse.SC_CREATED);
    } catch (PackageException pe) {
      pe.log(log);
      throw new DAVStatusException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, pe.toString());
    } catch (CrosswalkException ie) {
      String reason = "";
      if (ie.getCause() != null) {
        reason = ", Reason: " + ie.getCause().toString();
      }
      log.error(ie.toString() + reason);
      throw new DAVStatusException(
          HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ie.toString() + reason);
    }
  }
/**
 * Class implementing static helpers for anywhere that interacts with the sort columns (ie.
 * ItemsByAuthor.sort_author, ItemsByTitle.sort_title)
 *
 * <p>This class maps index 'types' to delegates that implement the sort string creation
 *
 * <p>Types can be defined or configured using the plugin manager:
 *
 * <p>plugin.named.org.dspace.sort.OrderFormatDelegate= org.dspace.sort.OrderFormatTitleMarc21=title
 * org.dspace.sort.OrderFormatAuthor=author
 *
 * <p>The following standard types have been defined by default, but can be reconfigured via the
 * plugin manager:
 *
 * <p>author = org.dspace.sort.OrderFormatAuthor title = org.dspace.sort.OrderFormatTitle text =
 * org.dspace.sort.OrderFormatText
 *
 * <p>IMPORTANT - If you change any of the orderings, you need to rebuild the browse sort columns
 * (ie. run 'index-all', or 'dsrun org.dspace.browse.InitializeBrowse')
 *
 * @author Graham Triggs
 * @version $Revision: 1.0 $
 */
public class OrderFormat {
  private static final Logger log = LogManager.getLogger(OrderFormat.class);

  public static final String AUTHOR = "author";
  public static final String TITLE = "title";
  public static final String TEXT = "text";

  // Array of all available order delegates - avoids excessive calls to plugin manager
  private static final String[] delegates =
      PluginManager.getAllPluginNames(OrderFormatDelegate.class);

  private static final OrderFormatDelegate authorDelegate = new OrderFormatAuthor();
  private static final OrderFormatDelegate titleDelegate = new OrderFormatTitle();
  private static final OrderFormatDelegate textDelegate = new OrderFormatText();

  /** Generate a sort string for the given DC metadata */
  public static String makeSortString(String value, String language, String type) {
    OrderFormatDelegate delegate = null;

    // If there is no value, return null
    if (value == null) return null;

    // If a named index has been supplied
    if (type != null && type.length() > 0) {
      // Use a delegate if one is configured
      if ((delegate = OrderFormat.getDelegate(type)) != null) {
        return delegate.makeSortString(value, language);
      }

      // No delegates found, so apply defaults
      if (type.equalsIgnoreCase(OrderFormat.AUTHOR) && authorDelegate != null) {
        return authorDelegate.makeSortString(value, language);
      }

      if (type.equalsIgnoreCase(OrderFormat.TITLE) && titleDelegate != null) {
        return titleDelegate.makeSortString(value, language);
      }

      if (type.equalsIgnoreCase(OrderFormat.TEXT) && textDelegate != null) {
        return textDelegate.makeSortString(value, language);
      }
    }

    return value;
  }

  /** Retrieve the named delegate */
  private static OrderFormatDelegate getDelegate(String name) {
    if (name != null && name.length() > 0) {
      // Check the cached array of names to see if the delegate has been configured
      for (int idx = 0; idx < delegates.length; idx++) {
        if (delegates[idx].equals(name)) {
          return (OrderFormatDelegate)
              PluginManager.getNamedPlugin(OrderFormatDelegate.class, name);
        }
      }
    }

    return null;
  }
}
  /**
   * Simple command-line rig for testing the DIM output of a stylesheet. Usage: java
   * XSLTIngestionCrosswalk <crosswalk-name> <input-file>
   */
  public static void main(String[] argv) throws Exception {
    if (argv.length < 2) {
      System.err.println("Usage:  java XSLTIngestionCrosswalk [-l] <crosswalk-name> <input-file>");
      System.exit(1);
    }

    int i = 0;
    boolean list = false;
    // skip first arg if it's the list option
    if (argv.length > 2 && argv[0].equals("-l")) {
      ++i;
      list = true;
    }
    IngestionCrosswalk xwalk =
        (IngestionCrosswalk) PluginManager.getNamedPlugin(IngestionCrosswalk.class, argv[i]);
    if (xwalk == null) {
      System.err.println(
          "Error, cannot find an IngestionCrosswalk plugin for: \"" + argv[i] + "\"");
      System.exit(1);
    }

    XSLTransformer xform = ((XSLTIngestionCrosswalk) xwalk).getTransformer(DIRECTION);
    if (xform == null)
      throw new CrosswalkInternalException(
          "Failed to initialize transformer, probably error loading stylesheet.");

    SAXBuilder builder = new SAXBuilder();
    Document inDoc = builder.build(new FileInputStream(argv[i + 1]));
    XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
    Document dimDoc = null;
    List dimList = null;
    if (list) {
      dimList = xform.transform(inDoc.getRootElement().getChildren());
      outputter.output(dimList, System.out);
    } else {
      dimDoc = xform.transform(inDoc);
      outputter.output(dimDoc, System.out);
      dimList = dimDoc.getRootElement().getChildren();
    }

    // Sanity-check the generated DIM, make sure it would load.
    Context context = new Context();
    Iterator di = dimList.iterator();
    while (di.hasNext()) {
      // skip over comment, text and other trash some XSLs generate..
      Object o = di.next();
      if (!(o instanceof Element)) continue;

      Element elt = (Element) o;
      if (elt.getName().equals("field") && elt.getNamespace().equals(DIM_NS)) {
        String schema = elt.getAttributeValue("mdschema");
        String element = elt.getAttributeValue("element");
        String qualifier = elt.getAttributeValue("qualifier");
        MetadataSchema ms = MetadataSchema.find(context, schema);
        if (ms == null) {
          System.err.println(
              "DIM Error, Cannot find metadata schema for: schema=\""
                  + schema
                  + "\" (... element=\""
                  + element
                  + "\", qualifier=\""
                  + qualifier
                  + "\")");
        } else {
          if (qualifier != null && qualifier.equals("")) {
            System.err.println(
                "DIM Warning, qualifier is empty string: "
                    + " schema=\""
                    + schema
                    + "\", element=\""
                    + element
                    + "\", qualifier=\""
                    + qualifier
                    + "\"");
            qualifier = null;
          }
          MetadataField mf =
              MetadataField.findByElement(context, ms.getSchemaID(), element, qualifier);
          if (mf == null)
            System.err.println(
                "DIM Error, Cannot find metadata field for: schema=\""
                    + schema
                    + "\", element=\""
                    + element
                    + "\", qualifier=\""
                    + qualifier
                    + "\"");
        }
      } else {
        // ("Got unexpected element in DIM list: "+elt.toString());
        throw new MetadataValidationException(
            "Got unexpected element in DIM list: " + elt.toString());
      }
    }
  }