Beispiel #1
0
  /**
   * each entry represents a bitstream....
   *
   * @param c
   * @param i
   * @param path
   * @param fileName
   * @param bundleName
   * @throws SQLException
   * @throws IOException
   * @throws AuthorizeException
   */
  private void processContentFileEntry(
      Context c, Item i, String path, String fileName, String bundleName, boolean primary)
      throws SQLException, IOException, AuthorizeException {
    String fullpath = path + File.separatorChar + fileName;

    // get an input stream
    BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fullpath));

    Bitstream bs = null;
    String newBundleName = bundleName;

    if (bundleName == null) {
      // is it license.txt?
      if ("license.txt".equals(fileName)) {
        newBundleName = "LICENSE";
      } else {
        // call it ORIGINAL
        newBundleName = "ORIGINAL";
      }
    }

    if (!isTest) {
      // find the bundle
      Bundle[] bundles = i.getBundles(newBundleName);
      Bundle targetBundle = null;

      if (bundles.length < 1) {
        // not found, create a new one
        targetBundle = i.createBundle(newBundleName);
      } else {
        // put bitstreams into first bundle
        targetBundle = bundles[0];
      }

      // now add the bitstream
      bs = targetBundle.createBitstream(bis);

      bs.setName(fileName);

      // Identify the format
      // FIXME - guessing format guesses license.txt incorrectly as a text
      // file format!
      BitstreamFormat bf = FormatIdentifier.guessFormat(c, bs);
      bs.setFormat(bf);

      // Is this a the primary bitstream?
      if (primary) {
        targetBundle.setPrimaryBitstreamID(bs.getID());
        targetBundle.update();
      }

      bs.update();
    }

    bis.close();
  }
Beispiel #2
0
  /**
   * Register the bitstream file into DSpace
   *
   * @param c
   * @param i
   * @param assetstore
   * @param bitstreamPath the full filepath expressed in the contents file
   * @param bundleName
   * @throws SQLException
   * @throws IOException
   * @throws AuthorizeException
   */
  private void registerBitstream(
      Context c, Item i, int assetstore, String bitstreamPath, String bundleName)
      throws SQLException, IOException, AuthorizeException {
    // TODO validate assetstore number
    // TODO make sure the bitstream is there

    Bitstream bs = null;
    String newBundleName = bundleName;

    if (bundleName == null) {
      // is it license.txt?
      if (bitstreamPath.endsWith("license.txt")) {
        newBundleName = "LICENSE";
      } else {
        // call it ORIGINAL
        newBundleName = "ORIGINAL";
      }
    }

    if (!isTest) {
      // find the bundle
      Bundle[] bundles = i.getBundles(newBundleName);
      Bundle targetBundle = null;

      if (bundles.length < 1) {
        // not found, create a new one
        targetBundle = i.createBundle(newBundleName);
      } else {
        // put bitstreams into first bundle
        targetBundle = bundles[0];
      }

      // now add the bitstream
      bs = targetBundle.registerBitstream(assetstore, bitstreamPath);

      // set the name to just the filename
      int iLastSlash = bitstreamPath.lastIndexOf('/');
      bs.setName(bitstreamPath.substring(iLastSlash + 1));

      // Identify the format
      // FIXME - guessing format guesses license.txt incorrectly as a text file format!
      BitstreamFormat bf = FormatIdentifier.guessFormat(c, bs);
      bs.setFormat(bf);

      bs.update();
    }
  }
  /**
   * Process Item, correcting CC-License if encountered.
   *
   * @param item
   * @throws SQLException
   * @throws AuthorizeException
   * @throws IOException
   */
  protected static void handleItem(Item item) throws SQLException, AuthorizeException, IOException {
    Bundle[] bundles = item.getBundles("CC-LICENSE");

    if (bundles == null || bundles.length == 0) return;

    Bundle bundle = bundles[0];

    Bitstream bitstream = bundle.getBitstreamByName("license_rdf");

    String license_rdf = new String(copy(bitstream));

    /* quickly fix xml by ripping out offensive parts */
    license_rdf = license_rdf.replaceFirst("<license", "");
    license_rdf = license_rdf.replaceFirst("</license>", "");

    StringWriter result = new StringWriter();

    try {
      templates
          .newTransformer()
          .transform(
              new StreamSource(new ByteArrayInputStream(license_rdf.getBytes())),
              new StreamResult(result));
    } catch (TransformerException e) {
      throw new RuntimeException(e.getMessage(), e);
    }

    StringBuffer buffer = result.getBuffer();

    Bitstream newBitstream =
        bundle.createBitstream(new ByteArrayInputStream(buffer.toString().getBytes()));

    newBitstream.setName(bitstream.getName());
    newBitstream.setDescription(bitstream.getDescription());
    newBitstream.setFormat(bitstream.getFormat());
    newBitstream.setSource(bitstream.getSource());
    newBitstream.setUserFormatDescription(bitstream.getUserFormatDescription());
    newBitstream.update();

    bundle.removeBitstream(bitstream);

    bundle.update();
  }
Beispiel #4
0
  /**
   * Perform a deposit, using the supplied SWORD Deposit object.
   *
   * @param deposit
   * @throws SWORDErrorException
   * @throws DSpaceSWORDException
   */
  public DepositResult doDeposit(Deposit deposit) throws SWORDErrorException, DSpaceSWORDException {
    // get the things out of the service that we need
    Context context = swordService.getContext();
    SWORDConfiguration swordConfig = swordService.getSwordConfig();
    SWORDUrlManager urlManager = swordService.getUrlManager();

    // FIXME: the spec is unclear what to do in this situation.  I'm going
    // the throw a 415 (ERROR_CONTENT) until further notice
    //
    // determine if this is an acceptable file format
    if (!swordConfig.isAcceptableContentType(context, deposit.getContentType(), collection)) {
      log.error(
          "Unacceptable content type detected: "
              + deposit.getContentType()
              + " for collection "
              + collection.getID());
      throw new SWORDErrorException(
          ErrorCodes.ERROR_CONTENT,
          "Unacceptable content type in deposit request: " + deposit.getContentType());
    }

    // determine if this is an acceptable packaging type for the deposit
    // if not, we throw a 415 HTTP error (Unsupported Media Type, ERROR_CONTENT)
    if (!swordConfig.isSupportedMediaType(deposit.getPackaging(), this.collection)) {
      log.error(
          "Unacceptable packaging type detected: "
              + deposit.getPackaging()
              + "for collection"
              + collection.getID());
      throw new SWORDErrorException(
          ErrorCodes.ERROR_CONTENT,
          "Unacceptable packaging type in deposit request: " + deposit.getPackaging());
    }

    // Obtain the relevant ingester from the factory
    SWORDIngester si = SWORDIngesterFactory.getInstance(context, deposit, collection);
    swordService.message("Loaded ingester: " + si.getClass().getName());

    // do the deposit
    DepositResult result = si.ingest(swordService, deposit, collection);
    swordService.message("Archive ingest completed successfully");

    // if there's an item availalble, and we want to keep the original
    // then do that
    try {
      if (swordConfig.isKeepOriginal()) {
        swordService.message(
            "DSpace will store an original copy of the deposit, "
                + "as well as ingesting the item into the archive");

        // in order to be allowed to add the file back to the item, we need to ignore authorisations
        // for a moment
        boolean ignoreAuth = context.ignoreAuthorization();
        context.setIgnoreAuthorization(true);

        String bundleName = ConfigurationManager.getProperty("sword-server", "bundle.name");
        if (bundleName == null || "".equals(bundleName)) {
          bundleName = "SWORD";
        }
        Item item = result.getItem();
        Bundle[] bundles = item.getBundles(bundleName);
        Bundle swordBundle = null;
        if (bundles.length > 0) {
          swordBundle = bundles[0];
        }
        if (swordBundle == null) {
          swordBundle = item.createBundle(bundleName);
        }

        String fn = swordService.getFilename(context, deposit, true);

        Bitstream bitstream;
        FileInputStream fis = null;
        try {
          fis = new FileInputStream(deposit.getFile());
          bitstream = swordBundle.createBitstream(fis);
        } finally {
          if (fis != null) {
            fis.close();
          }
        }

        bitstream.setName(fn);
        bitstream.setDescription("SWORD deposit package");

        BitstreamFormat bf = BitstreamFormat.findByMIMEType(context, deposit.getContentType());
        if (bf != null) {
          bitstream.setFormat(bf);
        }

        bitstream.update();

        swordBundle.update();
        item.update();

        swordService.message(
            "Original package stored as " + fn + ", in item bundle " + swordBundle);

        // now reset the context ignore authorisation
        context.setIgnoreAuthorization(ignoreAuth);

        // set the media link for the created item
        result.setMediaLink(urlManager.getMediaLink(bitstream));
      } else {
        // set the vanilla media link, which doesn't resolve to anything
        result.setMediaLink(urlManager.getBaseMediaLinkUrl());
      }
    } catch (SQLException e) {
      log.error("caught exception: ", e);
      throw new DSpaceSWORDException(e);
    } catch (AuthorizeException e) {
      log.error("caught exception: ", e);
      throw new DSpaceSWORDException(e);
    } catch (FileNotFoundException e) {
      log.error("caught exception: ", e);
      throw new DSpaceSWORDException(e);
    } catch (IOException e) {
      log.error("caught exception: ", e);
      throw new DSpaceSWORDException(e);
    }

    return result;
  }
Beispiel #5
0
  /**
   * perform the ingest using the given deposit object onto the specified target dspace object,
   * using the sword service implementation
   *
   * @param service
   * @param deposit
   * @param target
   * @return
   * @throws DSpaceSWORDException
   * @throws SWORDErrorException
   */
  public DepositResult ingest(SWORDService service, Deposit deposit, DSpaceObject target)
      throws DSpaceSWORDException, SWORDErrorException {
    try {
      if (!(target instanceof Item)) {
        throw new DSpaceSWORDException(
            "SimpleFileIngester can only be loaded for deposit onto DSpace Items");
      }
      Item item = (Item) target;

      // now set the sword service
      SWORDService swordService = service;

      // get the things out of the service that we need
      Context context = swordService.getContext();
      SWORDUrlManager urlManager = swordService.getUrlManager();

      Bundle[] bundles = item.getBundles("ORIGINAL");
      Bundle original;
      if (bundles.length > 0) {
        original = bundles[0];
      } else {
        original = item.createBundle("ORIGINAL");
      }

      Bitstream bs;
      FileInputStream fis = null;

      try {
        fis = new FileInputStream(deposit.getFile());
        bs = original.createBitstream(fis);
      } finally {
        if (fis != null) {
          fis.close();
        }
      }

      String fn = swordService.getFilename(context, deposit, false);
      bs.setName(fn);

      swordService.message("File created in item with filename " + fn);

      BitstreamFormat bf = BitstreamFormat.findByMIMEType(context, deposit.getContentType());
      if (bf != null) {
        bs.setFormat(bf);
      }

      // to do the updates, we need to ignore authorisation in the context
      boolean ignoreAuth = context.ignoreAuthorization();
      context.setIgnoreAuthorization(true);

      bs.update();
      original.update();
      item.update();

      // reset the ignore authorisation
      context.setIgnoreAuthorization(ignoreAuth);

      DepositResult result = new DepositResult();
      result.setHandle(urlManager.getBitstreamUrl(bs));
      result.setTreatment(this.getTreatment());
      result.setBitstream(bs);

      return result;
    } catch (SQLException e) {
      throw new DSpaceSWORDException(e);
    } catch (AuthorizeException e) {
      throw new DSpaceSWORDException(e);
    } catch (IOException e) {
      throw new DSpaceSWORDException(e);
    }
  }
Beispiel #6
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);
    }
  }
  /**
   * Create a new DSpace item out of a METS content package. All contents are dictated by the METS
   * manifest. Package is a ZIP archive, all files relative to top level and the manifest (as per
   * spec) in mets.xml.
   *
   * @param context - DSpace context.
   * @param collection - collection under which to create new item.
   * @param pkg - input stream containing package to ingest.
   * @param license - may be null, which takes default license.
   * @return workspace item created by ingest.
   * @throws PackageValidationException if package is unacceptable or there is a fatal error turning
   *     it into an Item.
   */
  public WorkspaceItem ingest(
      Context context,
      Collection collection,
      InputStream pkg,
      PackageParameters params,
      String license)
      throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException,
          IOException {
    BitstreamDAO bsDAO = BitstreamDAOFactory.getInstance(context);
    BitstreamFormatDAO bfDAO = BitstreamFormatDAOFactory.getInstance(context);
    BundleDAO bundleDAO = BundleDAOFactory.getInstance(context);
    WorkspaceItemDAO wsiDAO = WorkspaceItemDAOFactory.getInstance(context);

    ZipInputStream zip = new ZipInputStream(pkg);
    HashMap fileIdToBitstream = new HashMap();
    WorkspaceItem wi = null;
    boolean success = false;
    HashSet packageFiles = new HashSet();

    boolean validate = params.getBooleanProperty("validate", true);

    try {
      /* 1. Read all the files in the Zip into bitstreams first,
       *  because we only get to take one pass through a Zip input
       *  stream.  Give them temporary bitstream names corresponding
       *  to the same names they had in the Zip, since those MUST
       *  match the URL references in <Flocat> and <mdRef> elements.
       */
      METSManifest manifest = null;
      wi = wsiDAO.create(collection, false);
      Item item = wi.getItem();
      Bundle contentBundle = item.createBundle(Constants.CONTENT_BUNDLE_NAME);
      Bundle mdBundle = null;
      ZipEntry ze;
      while ((ze = zip.getNextEntry()) != null) {
        if (ze.isDirectory()) continue;
        Bitstream bs = null;
        String fname = ze.getName();
        if (fname.equals(MANIFEST_FILE)) {
          if (preserveManifest) {
            mdBundle = item.createBundle(Constants.METADATA_BUNDLE_NAME);
            bs = mdBundle.createBitstream(new PackageUtils.UnclosableInputStream(zip));
            bs.setName(fname);
            bs.setSource(fname);

            // Get magic bitstream format to identify manifest.
            BitstreamFormat manifestFormat = null;
            manifestFormat =
                PackageUtils.findOrCreateBitstreamFormat(
                    context,
                    MANIFEST_BITSTREAM_FORMAT,
                    "application/xml",
                    MANIFEST_BITSTREAM_FORMAT + " package manifest");
            bs.setFormat(manifestFormat);

            manifest = METSManifest.create(bs.retrieve(), validate);
          } else {
            manifest = METSManifest.create(new PackageUtils.UnclosableInputStream(zip), validate);
            continue;
          }
        } else {
          bs = contentBundle.createBitstream(new PackageUtils.UnclosableInputStream(zip));
          bs.setSource(fname);
          bs.setName(fname);
        }
        packageFiles.add(fname);
        bs.setSource(fname);
        bsDAO.update(bs);
      }
      zip.close();

      if (manifest == null)
        throw new PackageValidationException(
            "No METS Manifest found (filename=" + MANIFEST_FILE + ").  Package is unacceptable.");

      // initial sanity checks on manifest (in subclass)
      checkManifest(manifest);

      /* 2. Grovel a file list out of METS Manifest and compare
       *  it to the files in package, as an integrity test.
       */
      List manifestContentFiles = manifest.getContentFiles();

      // Compare manifest files with the ones found in package:
      //  a. Start with content files (mentioned in <fileGrp>s)
      HashSet missingFiles = new HashSet();
      for (Iterator mi = manifestContentFiles.iterator(); mi.hasNext(); ) {
        // First locate corresponding Bitstream and make
        // map of Bitstream to <file> ID.
        Element mfile = (Element) mi.next();
        String mfileId = mfile.getAttributeValue("ID");
        if (mfileId == null)
          throw new PackageValidationException(
              "Invalid METS Manifest: file element without ID attribute.");
        String path = METSManifest.getFileName(mfile);
        Bitstream bs = contentBundle.getBitstreamByName(path);
        if (bs == null) {
          log.warn(
              "Cannot find bitstream for filename=\""
                  + path
                  + "\", skipping it..may cause problems later.");
          missingFiles.add(path);
        } else {
          fileIdToBitstream.put(mfileId, bs);

          // Now that we're done using Name to match to <file>,
          // set default bitstream Name to last path element;
          // Zip entries all have '/' pathname separators
          // NOTE: set default here, hopefully crosswalk of
          // a bitstream techMD section will override it.
          String fname = bs.getName();
          int lastSlash = fname.lastIndexOf('/');
          if (lastSlash >= 0 && lastSlash + 1 < fname.length())
            bs.setName(fname.substring(lastSlash + 1));

          // Set Default bitstream format:
          //  1. attempt to guess from MIME type
          //  2. if that fails, guess from "name" extension.
          String mimeType = mfile.getAttributeValue("MIMETYPE");
          BitstreamFormat bf = (mimeType == null) ? null : bfDAO.retrieveByMimeType(mimeType);
          if (bf == null) bf = FormatIdentifier.guessFormat(context, bs);
          bs.setFormat(bf);

          // if this bitstream belongs in another Bundle, move it:
          String bundleName = manifest.getBundleName(mfile);
          if (!bundleName.equals(Constants.CONTENT_BUNDLE_NAME)) {
            Bundle bn;
            Bundle bns[] = item.getBundles(bundleName);
            if (bns != null && bns.length > 0) bn = bns[0];
            else bn = item.createBundle(bundleName);
            bn.addBitstream(bs);
            contentBundle.removeBitstream(bs);
          }

          // finally, build compare lists by deleting matches.
          if (packageFiles.contains(path)) packageFiles.remove(path);
          else missingFiles.add(path);
        }
      }

      //  b. Process files mentioned in <mdRef>s - check and move
      //     to METADATA bundle.
      for (Iterator mi = manifest.getMdFiles().iterator(); mi.hasNext(); ) {
        Element mdref = (Element) mi.next();
        String path = METSManifest.getFileName(mdref);

        // finally, build compare lists by deleting matches.
        if (packageFiles.contains(path)) packageFiles.remove(path);
        else missingFiles.add(path);

        // if there is a bitstream with that name in Content, move
        // it to the Metadata bundle:
        Bitstream mdbs = contentBundle.getBitstreamByName(path);
        if (mdbs != null) {
          if (mdBundle == null) mdBundle = item.createBundle(Constants.METADATA_BUNDLE_NAME);
          mdBundle.addBitstream(mdbs);
          contentBundle.removeBitstream(mdbs);
        }
      }

      // KLUDGE: make sure Manifest file doesn't get flagged as missing
      // or extra, since it won't be mentioned in the manifest.
      if (packageFiles.contains(MANIFEST_FILE)) packageFiles.remove(MANIFEST_FILE);

      // Give subclass a chance to refine the lists of in-package
      // and missing files, delete extraneous files, etc.
      checkPackageFiles(packageFiles, missingFiles, manifest);

      // Any discrepency in file lists is a fatal error:
      if (!(packageFiles.isEmpty() && missingFiles.isEmpty())) {
        StringBuffer msg =
            new StringBuffer("Package is unacceptable: contents do not match manifest.");
        if (!missingFiles.isEmpty()) {
          msg.append("\nPackage is missing these files listed in Manifest:");
          for (Iterator mi = missingFiles.iterator(); mi.hasNext(); )
            msg.append("\n\t" + (String) mi.next());
        }
        if (!packageFiles.isEmpty()) {
          msg.append("\nPackage contains extra files NOT in manifest:");
          for (Iterator mi = packageFiles.iterator(); mi.hasNext(); )
            msg.append("\n\t" + (String) mi.next());
        }
        throw new PackageValidationException(msg.toString());
      }

      /* 3. crosswalk the metadata
       */
      // get mdref'd streams from "callback" object.
      MdrefManager callback = new MdrefManager(mdBundle);

      chooseItemDmd(context, item, manifest, callback, manifest.getItemDmds());

      // crosswalk content bitstreams too.
      for (Iterator ei = fileIdToBitstream.entrySet().iterator(); ei.hasNext(); ) {
        Map.Entry ee = (Map.Entry) ei.next();
        manifest.crosswalkBitstream(
            context, (Bitstream) ee.getValue(), (String) ee.getKey(), callback);
      }

      // Take a second pass over files to correct names of derived files
      // (e.g. thumbnails, extracted text) to what DSpace expects:
      for (Iterator mi = manifestContentFiles.iterator(); mi.hasNext(); ) {
        Element mfile = (Element) mi.next();
        String bundleName = manifest.getBundleName(mfile);
        if (!bundleName.equals(Constants.CONTENT_BUNDLE_NAME)) {
          Element origFile = manifest.getOriginalFile(mfile);
          if (origFile != null) {
            String ofileId = origFile.getAttributeValue("ID");
            Bitstream obs = (Bitstream) fileIdToBitstream.get(ofileId);
            String newName = makeDerivedFilename(bundleName, obs.getName());
            if (newName != null) {
              String mfileId = mfile.getAttributeValue("ID");
              Bitstream bs = (Bitstream) fileIdToBitstream.get(mfileId);
              bs.setName(newName);
              bsDAO.update(bs);
            }
          }
        }
      }

      // Sanity-check the resulting metadata on the Item:
      PackageUtils.checkMetadata(item);

      /* 4. Set primary bitstream; same Bundle
       */
      Element pbsFile = manifest.getPrimaryBitstream();
      if (pbsFile != null) {
        Bitstream pbs = (Bitstream) fileIdToBitstream.get(pbsFile.getAttributeValue("ID"));
        if (pbs == null)
          log.error(
              "Got Primary Bitstream file ID="
                  + pbsFile.getAttributeValue("ID")
                  + ", but found no corresponding bitstream.");
        else {
          List<Bundle> bn = bundleDAO.getBundles(pbs);
          if (bn.size() > 0) bn.get(0).setPrimaryBitstreamID(pbs.getID());
          else log.error("Sanity check, got primary bitstream without any parent bundle.");
        }
      }

      // have subclass manage license since it may be extra package file.
      addLicense(context, collection, item, manifest, callback, license);

      // subclass hook for final checks and rearrangements
      finishItem(context, item);

      // commit any changes to bundles
      Bundle allBn[] = item.getBundles();
      for (int i = 0; i < allBn.length; ++i) {
        bundleDAO.update(allBn[i]);
      }

      wsiDAO.update(wi);
      success = true;
      log.info(
          LogManager.getHeader(
              context,
              "ingest",
              "Created new Item, db ID="
                  + String.valueOf(item.getID())
                  + ", WorkspaceItem ID="
                  + String.valueOf(wi.getID())));
      return wi;
    } catch (SQLException se) {
      // disable attempt to delete the workspace object, since
      // database may have suffered a fatal error and the
      // transaction rollback will get rid of it anyway.
      wi = null;

      // Pass this exception on to the next handler.
      throw se;
    } finally {
      // kill item (which also deletes bundles, bitstreams) if ingest fails
      if (!success && wi != null) wsiDAO.deleteAll(wi.getID());
    }
  }
Beispiel #8
0
  /**
   * Create new Item out of the ingested package, in the indicated collection. It creates a
   * workspace item, which the application can then install if it chooses to bypass Workflow.
   *
   * <p>This is a VERY crude import of a single Adobe PDF (Portable Document Format) file, using the
   * document's embedded metadata for package metadata. If the PDF file hasn't got the minimal
   * metadata available, it is rejected.
   *
   * <p>
   *
   * @param context DSpace context.
   * @param collection collection under which to create new item.
   * @param pkg input stream containing package to ingest.
   * @param params package parameters (none recognized)
   * @param license may be null, which takes default license.
   * @return workspace item created by ingest.
   * @throws PackageException if package is unacceptable or there is a fatal error turning it into
   *     an Item.
   */
  public WorkspaceItem ingest(
      Context context,
      Collection collection,
      InputStream pkg,
      PackageParameters params,
      String license)
      throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException,
          IOException {
    InputStream bis = null;
    COSDocument cos = null;
    boolean success = false;
    Bundle original = null;
    Bitstream bs = null;
    WorkspaceItem wi = null;

    /**
     * XXX comment out for now // XXX for debugging of parameter handling if (params != null) {
     * Enumeration pe = params.propertyNames(); while (pe.hasMoreElements()) { String name =
     * (String)pe.nextElement(); String v[] = params.getProperties(name); StringBuffer msg = new
     * StringBuffer("PackageParam: "); msg.append(name).append(" = "); for (int i = 0; i < v.length;
     * ++i) { if (i > 0) msg.append(", "); msg.append(v[i]); } log.debug(msg); } }
     */
    try {
      // Save the PDF in a bitstream first, since the parser
      // has to read it as well, and we cannot "rewind" it after that.
      wi = WorkspaceItem.create(context, collection, false);
      Item myitem = wi.getItem();
      original = myitem.createBundle("ORIGINAL");
      bs = original.createBitstream(pkg);
      pkg.close();
      bs.setName("package.pdf");
      setFormatToMIMEType(context, bs, "application/pdf");
      bs.update();
      log.debug("Created bitstream ID=" + String.valueOf(bs.getID()) + ", parsing...");

      crosswalkPDF(context, myitem, bs.retrieve());

      wi.update();
      context.commit();
      success = true;
      log.info(
          LogManager.getHeader(
              context,
              "ingest",
              "Created new Item, db ID="
                  + String.valueOf(myitem.getID())
                  + ", WorkspaceItem ID="
                  + String.valueOf(wi.getID())));
      return wi;
    } finally {
      try {
        // Close bitstream input stream and PDF file.
        if (bis != null) bis.close();
        if (cos != null) cos.close();
      } catch (IOException ie) {
      }

      // get rid of bitstream and item if ingest fails
      if (!success) {
        if (original != null && bs != null) original.removeBitstream(bs);
        if (wi != null) wi.deleteAll();
      }
      context.commit();
    }
  }
Beispiel #9
0
  /**
   * Process the upload of a new file!
   *
   * @param context current DSpace context
   * @param request current servlet request object
   * @param response current servlet response object
   * @param subInfo submission info object
   * @return Status or error flag which will be processed by UI-related code! (if STATUS_COMPLETE or
   *     0 is returned, no errors occurred!)
   */
  protected int processUploadFile(
      Context context,
      HttpServletRequest request,
      HttpServletResponse response,
      SubmissionInfo subInfo)
      throws ServletException, IOException, SQLException, AuthorizeException {
    boolean formatKnown = true;
    boolean fileOK = false;
    BitstreamFormat bf = null;
    Bitstream b = null;

    // NOTE: File should already be uploaded.
    // Manakin does this automatically via Cocoon.
    // For JSP-UI, the SubmissionController.uploadFiles() does the actual upload

    Enumeration attNames = request.getAttributeNames();

    // loop through our request attributes
    while (attNames.hasMoreElements()) {
      String attr = (String) attNames.nextElement();

      // if this ends with "-path", this attribute
      // represents a newly uploaded file
      if (attr.endsWith("-path")) {
        // strip off the -path to get the actual parameter
        // that the file was uploaded as
        String param = attr.replace("-path", "");

        // Load the file's path and input stream and description
        String filePath = (String) request.getAttribute(param + "-path");
        InputStream fileInputStream = (InputStream) request.getAttribute(param + "-inputstream");

        // attempt to get description from attribute first, then direct from a parameter
        String fileDescription = (String) request.getAttribute(param + "-description");
        if (fileDescription == null || fileDescription.length() == 0) {
          fileDescription = request.getParameter("description");
        }

        // if information wasn't passed by User Interface, we had a problem
        // with the upload
        if (filePath == null || fileInputStream == null) {
          return STATUS_UPLOAD_ERROR;
        }

        if (subInfo == null) {
          // In any event, if we don't have the submission info, the request
          // was malformed
          return STATUS_INTEGRITY_ERROR;
        }

        // Create the bitstream
        Item item = subInfo.getSubmissionItem().getItem();

        // do we already have a bundle?
        Bundle[] bundles = item.getBundles("ORIGINAL");

        if (bundles.length < 1) {
          // set bundle's name to ORIGINAL
          b = item.createSingleBitstream(fileInputStream, "ORIGINAL");
        } else {
          // we have a bundle already, just add bitstream
          b = bundles[0].createBitstream(fileInputStream);
        }

        // Strip all but the last filename. It would be nice
        // to know which OS the file came from.
        String noPath = filePath;

        while (noPath.indexOf('/') > -1) {
          noPath = noPath.substring(noPath.indexOf('/') + 1);
        }

        while (noPath.indexOf('\\') > -1) {
          noPath = noPath.substring(noPath.indexOf('\\') + 1);
        }

        b.setName(noPath);
        b.setSource(filePath);
        b.setDescription(fileDescription);

        // Identify the format
        bf = FormatIdentifier.guessFormat(context, b);
        b.setFormat(bf);

        // Update to DB
        b.update();
        item.update();

        if ((bf != null) && (bf.isInternal())) {
          log.warn("Attempt to upload file format marked as internal system use only");
          backoutBitstream(subInfo, b, item);
          return STATUS_UPLOAD_ERROR;
        }

        // Check for virus
        if (ConfigurationManager.getBooleanProperty("submission-curation", "virus-scan")) {
          Curator curator = new Curator();
          curator.addTask("vscan").curate(item);
          int status = curator.getStatus("vscan");
          if (status == Curator.CURATE_ERROR) {
            backoutBitstream(subInfo, b, item);
            return STATUS_VIRUS_CHECKER_UNAVAILABLE;
          } else if (status == Curator.CURATE_FAIL) {
            backoutBitstream(subInfo, b, item);
            return STATUS_CONTAINS_VIRUS;
          }
        }

        // If we got this far then everything is more or less ok.

        // Comment - not sure if this is the right place for a commit here
        // but I'm not brave enough to remove it - Robin.
        context.commit();

        // save this bitstream to the submission info, as the
        // bitstream we're currently working with
        subInfo.setBitstream(b);

        // if format was not identified
        if (bf == null) {
          return STATUS_UNKNOWN_FORMAT;
        }
      } // end if attribute ends with "-path"
    } // end while

    return STATUS_COMPLETE;
  }