/** * to avoid overwriting the undo source tree on repeated processing sequence numbers are added and * checked * * @param sourceDir - the original source directory * @return the directory of the undo archive * @throws FileNotFoundException * @throws IOException */ private File initUndoArchive(File sourceDir) throws FileNotFoundException, IOException { File parentDir = sourceDir.getAbsoluteFile().getParentFile(); if (parentDir == null) { throw new FileNotFoundException( "Parent directory of archive directory not found; unable to write UndoArchive; no processing performed"); } String sourceDirName = sourceDir.getName(); int seqNo = 1; File undoDir = new File(parentDir, "undo_" + sourceDirName + "_" + seqNo); while (undoDir.exists()) { undoDir = new File(parentDir, "undo_" + sourceDirName + "_" + ++seqNo); // increment } // create root directory if (!undoDir.mkdir()) { pr("ERROR creating Undo Archive directory "); throw new IOException("ERROR creating Undo Archive directory "); } // Undo is suppressed to prevent undo of undo File fSuppressUndo = new File(undoDir, ItemUpdate.SUPPRESS_UNDO_FILENAME); try { fSuppressUndo.createNewFile(); } catch (IOException e) { pr("ERROR creating Suppress Undo File " + e.toString()); throw e; } return undoDir; }
private void setEPerson(Context context, String eperson) throws Exception { if (eperson == null) { pr("Error - an eperson to do the importing must be specified"); pr(" (run with -h flag for details)"); throw new Exception("EPerson not specified."); } EPerson myEPerson = null; if (eperson.indexOf('@') != -1) { // @ sign, must be an email myEPerson = EPerson.findByEmail(context, eperson); } else { myEPerson = EPerson.find(context, Integer.parseInt(eperson)); } if (myEPerson == null) { pr("Error, eperson cannot be found: " + eperson); throw new Exception("Invalid EPerson"); } context.setCurrentUser(myEPerson); }
/** * 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()); } } } } }
/** @param argv */ public static void main(String[] argv) { // create an options object and populate it CommandLineParser parser = new PosixParser(); Options options = new Options(); // processing basis for determining items // item-specific changes with metadata in source directory with dublin_core.xml files options.addOption("s", "source", true, "root directory of source dspace archive "); // actions on items options.addOption( "a", "addmetadata", true, "add metadata specified for each item; multiples separated by semicolon ';'"); options.addOption("d", "deletemetadata", true, "delete metadata specified for each item"); options.addOption("A", "addbitstreams", false, "add bitstreams as specified for each item"); // extra work to get optional argument Option delBitstreamOption = new Option("D", "deletebitstreams", true, "delete bitstreams as specified for each item"); delBitstreamOption.setOptionalArg(true); delBitstreamOption.setArgName("BitstreamFilter"); options.addOption(delBitstreamOption); // other params options.addOption("e", "eperson", true, "email of eperson doing the update"); options.addOption( "i", "itemfield", true, "optional metadata field that containing item identifier; default is dc.identifier.uri"); options.addOption( "F", "filter-properties", true, "filter class name; only for deleting bitstream"); options.addOption("v", "verbose", false, "verbose logging"); // special run states options.addOption("t", "test", false, "test run - do not actually import items"); options.addOption( "P", "provenance", false, "suppress altering provenance field for bitstream changes"); options.addOption("h", "help", false, "help"); int status = 0; boolean isTest = false; boolean alterProvenance = true; String itemField = null; String metadataIndexName = null; Context context = null; ItemUpdate iu = new ItemUpdate(); try { CommandLine line = parser.parse(options, argv); if (line.hasOption('h')) { HelpFormatter myhelp = new HelpFormatter(); myhelp.printHelp("ItemUpdate", options); pr(""); pr("Examples:"); pr( " adding metadata: ItemUpdate -e [email protected] -s sourcedir -a dc.contributor -a dc.subject "); pr( " deleting metadata: ItemUpdate -e [email protected] -s sourcedir -d dc.description.other"); pr(" adding bitstreams: ItemUpdate -e [email protected] -s sourcedir -A -i dc.identifier"); pr(" deleting bitstreams: ItemUpdate -e [email protected] -s sourcedir -D ORIGINAL "); pr(""); System.exit(0); } if (line.hasOption('v')) { verbose = true; } if (line.hasOption('P')) { alterProvenance = false; pr("Suppressing changes to Provenance field option"); } iu.eperson = line.getOptionValue('e'); // db ID or email if (!line.hasOption('s')) // item specific changes from archive dir { pr("Missing source archive option"); System.exit(1); } String sourcedir = line.getOptionValue('s'); if (line.hasOption('t')) // test { isTest = true; pr("**Test Run** - not actually updating items."); } if (line.hasOption('i')) { itemField = line.getOptionValue('i'); } if (line.hasOption('d')) { String[] targetFields = line.getOptionValues('d'); DeleteMetadataAction delMetadataAction = (DeleteMetadataAction) iu.actionMgr.getUpdateAction(DeleteMetadataAction.class); delMetadataAction.addTargetFields(targetFields); // undo is an add for (String field : targetFields) { iu.undoActionList.add(" -a " + field + " "); } pr("Delete metadata for fields: "); for (String s : targetFields) { pr(" " + s); } } if (line.hasOption('a')) { String[] targetFields = line.getOptionValues('a'); AddMetadataAction addMetadataAction = (AddMetadataAction) iu.actionMgr.getUpdateAction(AddMetadataAction.class); addMetadataAction.addTargetFields(targetFields); // undo is a delete followed by an add of a replace record for target fields for (String field : targetFields) { iu.undoActionList.add(" -d " + field + " "); } for (String field : targetFields) { iu.undoActionList.add(" -a " + field + " "); } pr("Add metadata for fields: "); for (String s : targetFields) { pr(" " + s); } } if (line.hasOption('D')) // undo not supported { pr("Delete bitstreams "); String[] filterNames = line.getOptionValues('D'); if ((filterNames != null) && (filterNames.length > 1)) { pr("Error: Only one filter can be a used at a time."); System.exit(1); } String filterName = line.getOptionValue('D'); pr("Filter argument: " + filterName); if (filterName == null) // indicates using delete_contents files { DeleteBitstreamsAction delAction = (DeleteBitstreamsAction) iu.actionMgr.getUpdateAction(DeleteBitstreamsAction.class); delAction.setAlterProvenance(alterProvenance); } else { // check if param is on ALIAS list String filterClassname = filterAliases.get(filterName); if (filterClassname == null) { filterClassname = filterName; } BitstreamFilter filter = null; try { Class<?> cfilter = Class.forName(filterClassname); pr("BitstreamFilter class to instantiate: " + cfilter.toString()); filter = (BitstreamFilter) cfilter.newInstance(); // unfortunate cast, an erasure consequence } catch (Exception e) { pr("Error: Failure instantiating bitstream filter class: " + filterClassname); System.exit(1); } String filterPropertiesName = line.getOptionValue('F'); if (filterPropertiesName != null) // not always required { try { // TODO try multiple relative locations, e.g. source dir if (!filterPropertiesName.startsWith("/")) { filterPropertiesName = sourcedir + File.separator + filterPropertiesName; } filter.initProperties(filterPropertiesName); } catch (Exception e) { pr( "Error: Failure finding properties file for bitstream filter class: " + filterPropertiesName); System.exit(1); } } DeleteBitstreamsByFilterAction delAction = (DeleteBitstreamsByFilterAction) iu.actionMgr.getUpdateAction(DeleteBitstreamsByFilterAction.class); delAction.setAlterProvenance(alterProvenance); delAction.setBitstreamFilter(filter); // undo not supported } } if (line.hasOption('A')) { pr("Add bitstreams "); AddBitstreamsAction addAction = (AddBitstreamsAction) iu.actionMgr.getUpdateAction(AddBitstreamsAction.class); addAction.setAlterProvenance(alterProvenance); iu.undoActionList.add(" -D "); // delete_contents file will be written, no arg required } if (!iu.actionMgr.hasActions()) { pr("Error - an action must be specified"); System.exit(1); } else { pr("Actions to be performed: "); for (UpdateAction ua : iu.actionMgr) { pr(" " + ua.getClass().getName()); } } pr("ItemUpdate - initializing run on " + (new Date()).toString()); context = new Context(); iu.setEPerson(context, iu.eperson); context.setIgnoreAuthorization(true); HANDLE_PREFIX = ConfigurationManager.getProperty("handle.canonical.prefix"); if (HANDLE_PREFIX == null || HANDLE_PREFIX.length() == 0) { HANDLE_PREFIX = "http://hdl.handle.net/"; } iu.processArchive(context, sourcedir, itemField, metadataIndexName, alterProvenance, isTest); context.complete(); // complete all transactions context.setIgnoreAuthorization(false); } catch (Exception e) { if (context != null && context.isValid()) { context.abort(); context.setIgnoreAuthorization(false); } e.printStackTrace(); pr(e.toString()); status = 1; } if (isTest) { pr("***End of Test Run***"); } else { pr("End."); } System.exit(status); }
private void processArchive( Context context, String sourceDirPath, String itemField, String metadataIndexName, boolean alterProvenance, boolean isTest) throws Exception { // open and process the source directory File sourceDir = new File(sourceDirPath); if ((sourceDir == null) || !sourceDir.exists() || !sourceDir.isDirectory()) { pr("Error, cannot open archive source directory " + sourceDirPath); throw new Exception("error with archive source directory " + sourceDirPath); } String[] dircontents = sourceDir.list(directoryFilter); // just the names, not the path Arrays.sort(dircontents); // Undo is suppressed to prevent undo of undo boolean suppressUndo = false; File fSuppressUndo = new File(sourceDir, SUPPRESS_UNDO_FILENAME); if (fSuppressUndo.exists()) { suppressUndo = true; } File undoDir = null; // sibling directory of source archive if (!suppressUndo && !isTest) { undoDir = initUndoArchive(sourceDir); } int itemCount = 0; int successItemCount = 0; for (String dirname : dircontents) { itemCount++; pr(""); pr("processing item " + dirname); try { ItemArchive itarch = ItemArchive.create(context, new File(sourceDir, dirname), itemField); for (UpdateAction action : actionMgr) { pr("action: " + action.getClass().getName()); action.execute(context, itarch, isTest, suppressUndo); if (!isTest && !suppressUndo) { itarch.writeUndo(undoDir); } } if (!isTest) { Item item = itarch.getItem(); item.update(); // need to update before commit context.commit(); item.decache(); } ItemUpdate.pr("Item " + dirname + " completed"); successItemCount++; } catch (Exception e) { pr("Exception processing item " + dirname + ": " + e.toString()); } } if (!suppressUndo && !isTest) { StringBuilder sb = new StringBuilder("dsrun org.dspace.app.itemupdate.ItemUpdate "); sb.append(" -e ").append(this.eperson); sb.append(" -s ").append(undoDir); if (itemField != null) { sb.append(" -i ").append(itemField); } if (!alterProvenance) { sb.append(" -P "); } if (isTest) { sb.append(" -t "); } for (String actionOption : undoActionList) { sb.append(actionOption); } PrintWriter pw = null; try { File cmdFile = new File(undoDir.getParent(), undoDir.getName() + "_command.sh"); pw = new PrintWriter(new BufferedWriter(new FileWriter(cmdFile))); pw.println(sb.toString()); } finally { pw.close(); } } pr(""); pr( "Done processing. Successful items: " + successItemCount + " of " + itemCount + " items in source archive"); pr(""); }