public InputStream disseminate(Context context, Item item) throws DSpaceSwordException, SwordError, SwordServerException { try { Abdera abdera = new Abdera(); Feed feed = abdera.newFeed(); this.addMetadata(feed, item); Bundle[] originals = item.getBundles("ORIGINAL"); for (Bundle original : originals) { Bitstream[] bss = original.getBitstreams(); for (Bitstream bitstream : bss) { Entry entry = feed.addEntry(); this.populateEntry(context, entry, bitstream); } } ByteArrayOutputStream baos = new ByteArrayOutputStream(); feed.writeTo(baos); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); return bais; } catch (SQLException e) { throw new DSpaceSwordException(e); } catch (IOException e) { throw new DSpaceSwordException(e); } }
/** * Return this resource's children. Item's children are its bitstreams. * * @return the DAV resource[] * @throws SQLException the SQL exception */ @Override protected DAVResource[] children() throws SQLException { // Check for overall read permission on Item if (!AuthorizeManager.authorizeActionBoolean(this.context, this.item, Constants.READ)) { return new DAVResource[0]; } Vector result = new Vector(); Bundle[] bundles = this.item.getBundles(); for (Bundle element : bundles) { // check read permission on this Bundle if (!AuthorizeManager.authorizeActionBoolean(this.context, element, Constants.READ)) { continue; } Bitstream[] bitstreams = element.getBitstreams(); for (Bitstream element0 : bitstreams) { String ext[] = element0.getFormat().getExtensions(); result.add( new DAVBitstream( this.context, this.request, this.response, makeChildPath( DAVBitstream.getPathElt( element0.getSequenceID(), ext.length < 1 ? null : ext[0])), this.item, element0)); } } return (DAVResource[]) result.toArray(new DAVResource[result.size()]); }
/* (non-Javadoc) * @see uk.ac.jorum.packager.detector.BasePackageDetector#isValidPackage() */ @Override public boolean isValidPackage() { boolean result = false; boolean isUrl = false; try { // Download the feed // url is the bitstream contents // Check that the bitstream belongs in the FEED_BUNDLE - if it isn't then we may be looking at // raw content ie not a link to a feed! Bundle[] bundles = this.getBitstream().getBundles(); for (Bundle b : bundles) { if (b.getName().equals(Constants.FEED_BUNDLE)) { isUrl = true; break; } } if (isUrl) { Document xmlDoc = getRssDocument(this.getBitstream()); Element root = xmlDoc.getRootElement(); Attribute version = root.getAttribute("version"); if (root.getName().equals("rss") && version != null && version.getValue().equals("2.0")) { result = true; } } } catch (Exception e) { ExceptionLogger.logException(log, e); } return result; }
/** * 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(); }
// check whether any bundle belongs to any item that passed submission // and workflow process protected boolean isAnyItemInstalled(Context ctx, List<Bundle> bundles) throws SQLException { for (Bundle bundle : bundles) { for (Item item : bundle.getItems()) { if (workspaceItemService.findByItem(ctx, item) == null && workflowItemService.findByItem(ctx, item) == null) { return true; } } } return false; }
/** * Get the license for this Item as String. License is the first bitstream named "license.txt" in * a LICENSE bundle, apparently? * * <p>FIXME: is this correct? there's no counterexample.. * * @return license string, or null if none found. * @throws SQLException the SQL exception * @throws AuthorizeException the authorize exception * @throws IOException Signals that an I/O exception has occurred. */ private String getLicenseAsString() throws SQLException, AuthorizeException, IOException { Bundle lb[] = this.item.getBundles(Constants.LICENSE_BUNDLE_NAME); for (Bundle element : lb) { Bitstream lbs = element.getBitstreamByName("license.txt"); if (lbs != null) { ByteArrayOutputStream baos = new ByteArrayOutputStream((int) lbs.getSize()); Utils.copy(lbs.retrieve(), baos); return baos.toString(); } } return null; }
@Override public int perform(DSpaceObject dso) throws IOException { status = Curator.CURATE_SKIP; logDebugMessage("The target dso is " + dso.getName()); if (dso instanceof Item) { status = Curator.CURATE_SUCCESS; Item item = (Item) dso; try { openSession(); } catch (IOException ioE) { // no point going further - set result and error out closeSession(); setResult(CONNECT_FAIL_MESSAGE); return Curator.CURATE_ERROR; } try { Bundle bundle = item.getBundles("ORIGINAL")[0]; results = new ArrayList<String>(); for (Bitstream bitstream : bundle.getBitstreams()) { InputStream inputstream = bitstream.retrieve(); logDebugMessage("Scanning " + bitstream.getName() + " . . . "); int bstatus = scan(bitstream, inputstream, getItemHandle(item)); inputstream.close(); if (bstatus == Curator.CURATE_ERROR) { // no point going further - set result and error out setResult(SCAN_FAIL_MESSAGE); status = bstatus; break; } if (failfast && bstatus == Curator.CURATE_FAIL) { status = bstatus; break; } else if (bstatus == Curator.CURATE_FAIL && status == Curator.CURATE_SUCCESS) { status = bstatus; } } } catch (AuthorizeException authE) { throw new IOException(authE.getMessage(), authE); } catch (SQLException sqlE) { throw new IOException(sqlE.getMessage(), sqlE); } finally { closeSession(); } if (status != Curator.CURATE_ERROR) { formatResults(item); } } return status; }
protected void addGroupPolicyToItem(Context context, Item item, int type, Group group) throws AuthorizeException, SQLException { if (group != null) { authorizeService.addPolicy(context, item, type, group); List<Bundle> bundles = item.getBundles(); for (Bundle bundle : bundles) { authorizeService.addPolicy(context, bundle, type, group); List<Bitstream> bits = bundle.getBitstreams(); for (Bitstream bit : bits) { authorizeService.addPolicy(context, bit, type, group); } } } }
/** * Tests bitstream for membership in specified bundles (ORIGINAL, TEXT, THUMBNAIL) * * @param bitstream * @throws BitstreamFilterException * @returns true if bitstream is in specified bundles */ public boolean accept(Bitstream bitstream) throws BitstreamFilterException { try { Bundle[] bundles = bitstream.getBundles(); for (Bundle b : bundles) { for (String bn : bundlesToEmpty) { if (b.getName().equals(bn)) { return true; } } } } catch (SQLException e) { throw new BitstreamFilterException(e); } return false; }
/** * Delete bitstream from item * * @param context * @param ItemArchive * @param isTest * @param suppressUndo * @throws IllegalArgumentException * @throws ParseException * @throws IOException * @throws AuthorizeException * @throws SQLException */ public void execute(Context context, ItemArchive itarch, boolean isTest, boolean suppressUndo) throws IllegalArgumentException, IOException, SQLException, AuthorizeException, ParseException { File f = new File(itarch.getDirectory(), ItemUpdate.DELETE_CONTENTS_FILE); if (!f.exists()) { ItemUpdate.pr( "Warning: Delete_contents file for item " + itarch.getDirectoryName() + " not found."); } else { List<Integer> list = MetadataUtilities.readDeleteContentsFile(f); if (list.isEmpty()) { ItemUpdate.pr("Warning: empty delete_contents file for item " + itarch.getDirectoryName()); } else { for (int id : list) { try { Bitstream bs = Bitstream.find(context, id); if (bs == null) { ItemUpdate.pr("Bitstream not found by id: " + id); } else { Bundle[] bundles = bs.getBundles(); for (Bundle b : bundles) { if (isTest) { ItemUpdate.pr("Delete bitstream with id = " + id); } else { b.removeBitstream(bs); ItemUpdate.pr("Deleted bitstream with id = " + id); } } if (alterProvenance) { DtoMetadata dtom = DtoMetadata.create("dc.description.provenance", "en", ""); String append = "Bitstream " + bs.getName() + " deleted on " + DCDate.getCurrent() + "; "; Item item = bundles[0].getItems()[0]; ItemUpdate.pr("Append provenance with: " + append); if (!isTest) { MetadataUtilities.appendMetadata(item, dtom, false, append); } } } } catch (SQLException e) { ItemUpdate.pr("Error finding bitstream from id: " + id + " : " + e.toString()); } } } } }
protected void removeGroupItemPolicies(Context context, Item item, Group e) throws SQLException, AuthorizeException { if (e != null) { // Also remove any lingering authorizations from this user authorizeService.removeGroupPolicies(context, item, e); // Remove the bundle rights List<Bundle> bundles = item.getBundles(); for (Bundle bundle : bundles) { authorizeService.removeGroupPolicies(context, bundle, e); List<Bitstream> bitstreams = bundle.getBitstreams(); for (Bitstream bitstream : bitstreams) { authorizeService.removeGroupPolicies(context, bitstream, e); } } } }
/** * 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(); } }
/** * Find the local Bitstream referenced in an <code>mdRef</code> element. * * @param mdref the METS mdRef element to locate the bitstream for. * @return bitstream or null if none found. */ public Bitstream getBitstreamForMdRef(Element mdref) throws MetadataValidationException, IOException, SQLException, AuthorizeException { String path = METSManifest.getFileName(mdref); if (mdBundle == null) throw new MetadataValidationException( "Failed referencing mdRef element, because there were no metadata files."); return mdBundle.getBitstreamByName(path); }
/** * 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(); }
protected void removeUserItemPolicies(Context context, Item item, EPerson e) throws SQLException, AuthorizeException { if (e != null) { // Also remove any lingering authorizations from this user authorizeService.removeEPersonPolicies(context, item, e); // Remove the bundle rights List<Bundle> bundles = item.getBundles(); for (Bundle bundle : bundles) { authorizeService.removeEPersonPolicies(context, bundle, e); List<Bitstream> bitstreams = bundle.getBitstreams(); for (Bitstream bitstream : bitstreams) { authorizeService.removeEPersonPolicies(context, bitstream, e); } } // Ensure that the submitter always retains his resource policies if (e.getID().equals(item.getSubmitter().getID())) { grantSubmitterReadPolicies(context, item); } } }
@Override public void unlink(Item item, Bundle bundle) throws AuthorizeException { if (!linked(item, bundle)) { return; } try { // Remove bundle mappings from DB DatabaseManager.updateQuery( context, "DELETE FROM item2bundle WHERE item_id= ? " + "AND bundle_id= ? ", item.getID(), bundle.getID()); } catch (SQLException sqle) { throw new RuntimeException(sqle); } }
@Override public List<Item> getParentItems(Bundle bundle) { try { // Get items TableRowIterator tri = DatabaseManager.queryTable( context, "item", "SELECT i.item_id FROM item i, item2bundle i2b " + "WHERE i2b.item_id = i.item_id " + "AND i2b.bundle_id = ? ", bundle.getID()); return returnAsList(tri); } catch (SQLException sqle) { throw new RuntimeException(sqle); } }
@Override public void link(Item item, Bundle bundle) throws AuthorizeException { if (linked(item, bundle)) { return; } try { TableRow row = DatabaseManager.create(context, "item2bundle"); row.setColumn("item_id", item.getID()); row.setColumn("bundle_id", bundle.getID()); DatabaseManager.update(context, row); // If we're adding the Bundle to the Item, we bequeath our // policies unto it. AuthorizeManager.inheritPolicies(context, item, bundle); } catch (SQLException sqle) { throw new RuntimeException(sqle); } }
@Override public boolean linked(Item item, Bundle bundle) { try { TableRowIterator tri = DatabaseManager.query( context, "SELECT id FROM item2bundle " + " WHERE item_id=" + item.getID() + " AND bundle_id=" + bundle.getID()); boolean result = tri.hasNext(); tri.close(); return result; } catch (SQLException sqle) { throw new RuntimeException(sqle); } }
/** Add rights information. This attaches an href to the URL of the item's licence file */ protected void addRights() throws DSpaceSWORDException { try { // work our way up to the item List<Bundle> bundle2bitstreams = this.bitstream.getBundles(); if (bundle2bitstreams.isEmpty()) { log.error("Found orphaned bitstream: " + bitstream.getID()); throw new DSpaceSWORDException("Orphaned bitstream discovered"); } Bundle bundle = bundle2bitstreams.get(0); List<Item> items = bundle.getItems(); if (items.isEmpty()) { log.error("Found orphaned bundle: " + bundle.getID()); throw new DSpaceSWORDException("Orphaned bundle discovered"); } Item item = items.get(0); // now get the licence out of the item SWORDUrlManager urlManager = swordService.getUrlManager(); StringBuilder rightsString = new StringBuilder(); List<Bundle> lbundles = item.getBundles(); for (Bundle lbundle : lbundles) { if (!Constants.LICENSE_BUNDLE_NAME.equals(lbundle.getName())) { // skip non-license bundles continue; } List<Bitstream> bss = lbundle.getBitstreams(); for (Bitstream bs : bss) { String url = urlManager.getBitstreamUrl(bs); rightsString.append(url).append(" "); } } Rights rights = new Rights(); rights.setContent(rightsString.toString()); rights.setType(ContentType.TEXT); entry.setRights(rights); log.debug("Added rights entry to entity"); } catch (SQLException e) { log.error("caught exception: ", e); throw new DSpaceSWORDException(e); } }
/** * 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; }
/** * 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); } }
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); } }
public void addBody(Body body) throws SQLException, WingException { // Get our parameters and state int itemID = parameters.getParameterAsInteger("itemID", -1); Item item = Item.find(context, itemID); String baseURL = contextPath + "/admin/item?administrative-continue=" + knot.getId(); // DIVISION: main div Division main = body.addInteractiveDivision( "edit-item-status", contextPath + "/admin/item", Division.METHOD_POST, "primary administrative item"); main.setHead(T_option_head); // LIST: options List options = main.addList("options", List.TYPE_SIMPLE, "horizontal"); options.addItem().addXref(baseURL + "&submit_status", T_option_status); options .addItem() .addHighlight("bold") .addXref(baseURL + "&submit_bitstreams", T_option_bitstreams); options.addItem().addXref(baseURL + "&submit_metadata", T_option_metadata); options.addItem().addXref(baseURL + "&view_item", T_option_view); // TABLE: Bitstream summary Table files = main.addTable("editItemBitstreams", 1, 1); files.setHead(T_head1); Row header = files.addRow(Row.ROLE_HEADER); header.addCellContent(T_column1); header.addCellContent(T_column2); header.addCellContent(T_column3); header.addCellContent(T_column4); header.addCellContent(T_column5); Bundle[] bundles = item.getBundles(); for (Bundle bundle : bundles) { Cell bundleCell = files.addRow().addCell(1, 5); bundleCell.addContent(T_bundle_label.parameterize(bundle.getName())); Bitstream[] bitstreams = bundle.getBitstreams(); for (Bitstream bitstream : bitstreams) { boolean primary = (bundle.getPrimaryBitstreamID() == bitstream.getID()); String name = bitstream.getName(); if (name != null && name.length() > 50) { // If the fiel name is too long the shorten it so that it will display nicely. String shortName = name.substring(0, 15); shortName += " ... "; shortName += name.substring(name.length() - 25, name.length()); name = shortName; } String description = bitstream.getDescription(); String format = null; BitstreamFormat bitstreamFormat = bitstream.getFormat(); if (bitstreamFormat != null) format = bitstreamFormat.getShortDescription(); String editURL = contextPath + "/admin/item?administrative-continue=" + knot.getId() + "&bitstreamID=" + bitstream.getID() + "&submit_edit"; String viewURL = contextPath + "/bitstream/id/" + bitstream.getID() + "/" + bitstream.getName(); Row row = files.addRow(); CheckBox remove = row.addCell().addCheckBox("remove"); remove.setLabel("remove"); remove.addOption(bundle.getID() + "/" + bitstream.getID()); if (!AuthorizeManager.authorizeActionBoolean(context, item, Constants.REMOVE)) { remove.setDisabled(); } if (AuthorizeManager.authorizeActionBoolean(context, bitstream, Constants.WRITE)) { // The user can edit the bitstream give them a link. Cell cell = row.addCell(); cell.addXref(editURL, name); if (primary) cell.addXref(editURL, T_primary_label); row.addCell().addXref(editURL, description); row.addCell().addXref(editURL, format); } else { // The user can't edit the bitstream just show them it. Cell cell = row.addCell(); cell.addContent(name); if (primary) cell.addContent(T_primary_label); row.addCell().addContent(description); row.addCell().addContent(format); } Highlight highlight = row.addCell().addHighlight("fade"); highlight.addContent("["); highlight.addXref(viewURL, T_view_link); highlight.addContent("]"); } } if (AuthorizeManager.authorizeActionBoolean(context, item, Constants.ADD)) { Cell cell = files.addRow().addCell(1, 5); cell.addXref( contextPath + "/admin/item?administrative-continue=" + knot.getId() + "&submit_add", T_submit_add); } else { Cell cell = files.addRow().addCell(1, 5); cell.addHighlight("fade").addContent(T_no_upload); } // PARA: actions Para actions = main.addPara("editItemActionsP", "editItemActionsP"); if (AuthorizeManager.authorizeActionBoolean(context, item, Constants.REMOVE)) actions.addButton("submit_delete").setValue(T_submit_delete); else { Button button = actions.addButton("submit_delete"); button.setValue(T_submit_delete); button.setDisabled(); main.addPara().addHighlight("fade").addContent(T_no_remove); } actions.addButton("submit_return").setValue(T_submit_return); main.addHidden("administrative-continue").setValue(knot.getId()); }
/** * 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()); } }
/** * 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(); } }