diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 737da6c3..f04b7810 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,18 +15,19 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v2 + uses: actions/checkout@v4 # https://github.com/actions/setup-java - - name: Install JDK 11 - uses: actions/setup-java@v2 + - name: Install JDK 17 + uses: actions/setup-java@v4 with: - distribution: zulu - java-version: 11 + distribution: 'temurin' + java-version: 17 + cache: 'maven' # https://github.com/actions/cache - name: Cache Maven dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: # Cache entire ~/.m2/repository path: ~/.m2/repository diff --git a/checkstyle-suppressions.xml b/checkstyle-suppressions.xml new file mode 100644 index 00000000..77e27b87 --- /dev/null +++ b/checkstyle-suppressions.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 00000000..a33fc483 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/modules/duracloud.cfg b/config/modules/duracloud.cfg index 374df2ff..17cd60bd 100644 --- a/config/modules/duracloud.cfg +++ b/config/modules/duracloud.cfg @@ -20,6 +20,9 @@ duracloud.port = 443 # http://demo.duracloud.org/[context]/[space-id]/[filename] duracloud.context = durastore +# DuraCloud Content Store ID +duracloud.store-id = 0 + # DuraCloud user name duracloud.username = rep-agent # DuraCloud password diff --git a/pom.xml b/pom.xml index c5f346b4..33401bfa 100644 --- a/pom.xml +++ b/pom.xml @@ -15,15 +15,16 @@ - - [7.2,7.20) + + [8.0,8.20) - 7.0.0 + 8.1.0 1.1.0 - 2.3.1 - - 11 + 4.0.2 + 4.0.5 + + 17 UTF-8 ${project.build.sourceEncoding} @@ -36,7 +37,7 @@ org.apache.maven.plugins maven-enforcer-plugin - 3.1.0 + 3.5.0 enforce-java @@ -87,7 +88,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.1 + 3.14.0 ${java.version} @@ -96,7 +97,7 @@ org.apache.maven.plugins maven-jar-plugin - 3.2.0 + 3.4.2 @@ -109,29 +110,67 @@ org.apache.maven.plugins maven-assembly-plugin - 3.2.0 + 3.7.1 org.apache.maven.plugins maven-dependency-plugin - 3.1.2 + 3.8.1 org.apache.maven.plugins maven-resources-plugin - 3.1.0 + 3.3.1 + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.6.0 + + + verify-style + + verify + + check + + + + + + src/main/java + + checkstyle.xml + true + true + + true + + checkstyle-suppressions.xml + checkstyle.suppressions.file + + + + + com.puppycrawl.tools + checkstyle + 8.45.1 + + org.sonatype.plugins nexus-staging-maven-plugin - 1.6.8 + 1.7.0 org.apache.maven.plugins maven-javadoc-plugin - 3.2.0 + 3.11.2 false @@ -141,13 +180,13 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + 3.3.1 org.apache.maven.plugins maven-gpg-plugin - 1.6 + 3.2.7 @@ -155,7 +194,7 @@ org.apache.maven.plugins maven-release-plugin - 2.5.3 + 3.1.1 release @@ -259,31 +298,43 @@ provided - org.slf4j - slf4j-log4j12 + commons-io + commons-io + + + javax.xml.bind + jaxb-api log4j log4j + + org.glassfish.jaxb + jaxb-runtime + + + org.slf4j + slf4j-log4j12 + junit junit - 4.13.1 + 4.13.2 test org.assertj assertj-core - 3.11.1 + 3.26.3 test org.mockito mockito-core - 3.8.0 + 3.12.4 test @@ -310,27 +361,27 @@ org.apache.logging.log4j log4j-api - 2.20.0 + 2.24.3 org.apache.logging.log4j log4j-core - 2.20.0 + 2.24.3 test - + - javax.xml.bind - jaxb-api - ${jaxb.version} + jakarta.xml.bind + jakarta.xml.bind-api + ${jaxb-api.version} compile org.glassfish.jaxb jaxb-runtime - ${jaxb.version} + ${jaxb-runtime.version} compile @@ -350,6 +401,14 @@ ch.qos.logback logback-classic + + javax.xml.bind + jaxb-api + + + org.glassfish.jaxb + jaxb-runtime + diff --git a/src/main/java/org/dspace/ctask/replicate/AbstractPackagerTask.java b/src/main/java/org/dspace/ctask/replicate/AbstractPackagerTask.java index 8a385a91..b453bed7 100644 --- a/src/main/java/org/dspace/ctask/replicate/AbstractPackagerTask.java +++ b/src/main/java/org/dspace/ctask/replicate/AbstractPackagerTask.java @@ -24,8 +24,7 @@ * @see org.dspace.content.packager.PackageDisseminator * @see org.dspace.content.packager.PackageIngester */ -public abstract class AbstractPackagerTask extends AbstractCurationTask -{ +public abstract class AbstractPackagerTask extends AbstractCurationTask { // Name of recursive mode option configurable in curation task configuration file private final String recursiveMode = "recursiveMode"; @@ -66,48 +65,38 @@ public abstract class AbstractPackagerTask extends AbstractCurationTask * @return configured PackageParameters (or null, if configurations not found) * @see org.dspace.content.packager.PackageParameters */ - protected PackageParameters loadPackagerParameters(String moduleName) - { - //Load up the replicate-mets.cfg file & all settings inside it + protected PackageParameters loadPackagerParameters(String moduleName) { + // Load up the replicate-mets.cfg file & all settings inside it List moduleProps = configurationService.getPropertyKeys(moduleName); PackageParameters pkgParams = new PackageParameters(); - //If our config file doesn't load properly, we'll return null - if(moduleProps!=null) - { - //loop through all properties in the config file - for(String property : moduleProps) - { - //Set propertyName, removing leading module name (if applicable) + // If our config file doesn't load properly, we'll return null + if (moduleProps != null) { + // loop through all properties in the config file + for (String property : moduleProps) { + // Set propertyName, removing leading module name (if applicable) String propertyName = property; - if(propertyName.startsWith(moduleName + ".")) { + if (propertyName.startsWith(moduleName + ".")) { propertyName = propertyName.replaceFirst(moduleName + ".", ""); } - //Only obey the setting(s) beginning with this task's ID/name, - if(propertyName.startsWith(this.taskId)) - { - //Parse out the option name by removing the "[taskID]." from beginning of property + // Only obey the setting(s) beginning with this task's ID/name, + if (propertyName.startsWith(this.taskId)) { + // Parse out the option name by removing the "[taskID]." from beginning of property String option = propertyName.replace(taskId + ".", ""); String value = configurationService.getProperty(property); - //Check which option is being set - if(option.equalsIgnoreCase(recursiveMode)) - { + // Check which option is being set + if (option.equalsIgnoreCase(recursiveMode)) { pkgParams.setRecursiveModeEnabled(Boolean.parseBoolean(value)); - } - else if (option.equals(useWorkflow)) - { + } else if (option.equals(useWorkflow)) { pkgParams.setWorkflowEnabled(Boolean.parseBoolean(value)); - } - else if (option.equals(useCollectionTemplate)) - { + } else if (option.equals(useCollectionTemplate)) { pkgParams.setUseCollectionTemplate(Boolean.parseBoolean(value)); - } - else //otherwise, assume the Packager will understand what to do with this option - { - //just set it as a property in PackageParameters + } else { + // otherwise, assume the Packager will understand what to do with this option + // just set it as a property in PackageParameters pkgParams.addProperty(option, value); } diff --git a/src/main/java/org/dspace/ctask/replicate/BagItReplaceWithAIP.java b/src/main/java/org/dspace/ctask/replicate/BagItReplaceWithAIP.java index 5240796d..d0d75d05 100644 --- a/src/main/java/org/dspace/ctask/replicate/BagItReplaceWithAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/BagItReplaceWithAIP.java @@ -57,7 +57,7 @@ public void init(Curator curator, String taskId) throws IOException { archFmt = configurationService.getProperty("replicate.packer.archfmt"); storeGroupName = configurationService.getProperty("replicate.group.aip.name"); } - + /** * Perform the 'Replace with AIP' task. *

@@ -70,7 +70,7 @@ public void init(Curator curator, String taskId) throws IOException { @Override public int perform(DSpaceObject dso) throws IOException { final ReplicaManager repMan = ReplicaManager.instance(); - + // overwrite with AIP data try { Context context = Curator.curationContext(); diff --git a/src/main/java/org/dspace/ctask/replicate/BagItReplicateConsumer.java b/src/main/java/org/dspace/ctask/replicate/BagItReplicateConsumer.java index 3acaa063..3d74eeb8 100644 --- a/src/main/java/org/dspace/ctask/replicate/BagItReplicateConsumer.java +++ b/src/main/java/org/dspace/ctask/replicate/BagItReplicateConsumer.java @@ -102,25 +102,32 @@ public class BagItReplicateConsumer implements Consumer { private final String archFmt = configurationService.getProperty("replicate.packer.archfmt"); @Override - public void initialize() throws Exception - { - repMan = ReplicaManager.instance(); + public void initialize() throws Exception { + try { + repMan = ReplicaManager.instance(); + } catch (IOException ioE) { + // The ReplicaManager attempts to initialize the ObjectStore specified in the configuration. + log.error("Unable to initialize the ReplicaManager. ", ioE); + } + taskQueue = (TaskQueue) pluginService.getSinglePlugin(TaskQueue.class); queueName = configurationService.getProperty("replicate.consumer.queue"); + // look for and load any idFilter files - excludes trump includes // An "idFilter" is an actual textual file named "exclude" or "include" // which contains a list of handles to filter from the Consumer - if (! loadIdFilter("exclude")) - { - if (loadIdFilter("include")) - { + if (!loadIdFilter("exclude")) { + if (loadIdFilter("include")) { idExclude = false; } } + taskQMap = new HashMap>(); taskPMap = new HashMap>(); + parseTasks("add"); parseTasks("mod"); + delMemIds = new ArrayList(); parseTasks("del"); } @@ -142,23 +149,21 @@ public void initialize() throws Exception * @throws Exception if error */ @Override - public void consume(Context ctx, Event event) throws Exception - { + public void consume(Context ctx, Event event) throws Exception { int evType = event.getEventType(); int subjType = event.getSubjectType(); + // This is the Handle of the object on which an event occured String id = event.getDetail(); - //System.out.println("got event type: " + evType + " for subject type: " + subjType); - switch (evType) - { + + // System.out.println("got event type: " + evType + " for subject type: " + subjType); + switch (evType) { case CREATE: //CREATE = Create a new object. case INSTALL: //INSTALL = Install an object (exits workflow/workspace). Only used for Items. // if NOT (Item & Create) // (i.e. We don't want to replicate items UNTIL they are Installed) - if (subjType != Constants.ITEM || evType != CREATE) - { - if (acceptId(id, event, ctx)) - { + if (subjType != Constants.ITEM || evType != CREATE) { + if (acceptId(id, event, ctx)) { // add it to the master lists of added/new objects // for which we need to perform tasks mapId(taskQMap, addQTasks, id); @@ -166,11 +171,10 @@ public void consume(Context ctx, Event event) throws Exception } } break; - case MODIFY: //MODIFY = modify an object - case MODIFY_METADATA: //MODIFY_METADATA = just modify an object's metadata + case MODIFY: // MODIFY = modify an object + case MODIFY_METADATA: // MODIFY_METADATA = just modify an object's metadata // If subject of event is null, this means the object was likely deleted - if (event.getSubject(ctx)==null) - { + if (event.getSubject(ctx) == null) { log.warn(event.getEventTypeAsString() + " event, could not get object for " + event.getSubjectTypeAsString() + " id=" + String.valueOf(event.getSubjectID()) @@ -178,15 +182,13 @@ public void consume(Context ctx, Event event) throws Exception break; } - //For MODIFY events, the Handle of modified object needs to be obtained from the Subject + // For MODIFY events, the Handle of modified object needs to be obtained from the Subject id = event.getSubject(ctx).getHandle(); // make sure handle resolves - these could be events // for a newly created item that hasn't been assigned a handle - if (id != null) - { + if (id != null) { // make sure we are supposed to process this object - if (acceptId(id, event, ctx)) - { + if (acceptId(id, event, ctx)) { // add it to the master lists of modified objects // for which we need to perform tasks mapId(taskQMap, modQTasks, id); @@ -194,11 +196,10 @@ public void consume(Context ctx, Event event) throws Exception } } break; - case REMOVE: //REMOVE = Remove an object from a container or group - case DELETE: //DELETE = Delete an object (actually destroy it) + case REMOVE: // REMOVE = Remove an object from a container or group + case DELETE: // DELETE = Delete an object (actually destroy it) // make sure we are supposed to process this object - if (acceptId(id, event, ctx)) - { // analyze & process the deletion/removal event + if (acceptId(id, event, ctx)) { // analyze & process the deletion/removal event deleteEvent(ctx, id, event); } break; @@ -208,38 +209,33 @@ public void consume(Context ctx, Event event) throws Exception } @Override - public void end(Context ctx) throws Exception - { + public void end(Context ctx) throws Exception { // if there are any pending objectIds, pass them to the curation // system to queue for later processing, or perform immediately EPerson ep = ctx.getCurrentUser(); String name = (ep != null) ? ep.getName() : "unknown"; long stamp = System.currentTimeMillis(); + // first the queueables Set entrySet = new HashSet(); - if (taskQMap.size() > 0) - { + if (!taskQMap.isEmpty()) { List taskList = new ArrayList(); - for (String task : taskQMap.keySet()) - { + for (String task : taskQMap.keySet()) { taskList.add(task); - for (String id : taskQMap.get(task)) - { + for (String id : taskQMap.get(task)) { entrySet.add(new TaskQueueEntry(name, stamp, taskList, id)); } taskList.clear(); } taskQMap.clear(); } + // now the performables - if (taskPMap.size() > 0) - { + if (!taskPMap.isEmpty()) { Curator curator = new Curator(); - for (String task : taskPMap.keySet()) - { + for (String task : taskPMap.keySet()) { curator.addTask(task); - for (String id : taskQMap.get(task)) - { + for (String id : taskQMap.get(task)) { curator.curate(ctx, id); } curator.clear(); @@ -248,23 +244,20 @@ public void end(Context ctx) throws Exception } // if there any uncommitted deletions, record them now - if (delObjId != null) - { - if (delTasks != null) - { + if (delObjId != null) { + if (delTasks != null) { entrySet.add(new TaskQueueEntry(name, stamp, delTasks, delObjId)); } processDelete(ctx); } - if (entrySet.size() > 0) - { + + if (!entrySet.isEmpty()) { taskQueue.enqueue(queueName, entrySet); } } @Override - public void finish(Context ctx) throws Exception - { + public void finish(Context ctx) throws Exception { // no-op } @@ -280,27 +273,25 @@ public void finish(Context ctx) throws Exception * @return true if this consumer should process this object event, false if it should not * @throws SQLException if database error occurs */ - private boolean acceptId(String id, Event event, Context ctx) throws SQLException - { + private boolean acceptId(String id, Event event, Context ctx) throws SQLException { // always accept if not filtering - if (idFilter == null) - { + if (idFilter == null) { return true; } + // filter supports only container ids - so if id is for an item, // find its owning collection String id2check = id; - if (event.getSubjectType() == Constants.ITEM) - { + if (event.getSubjectType() == Constants.ITEM) { // NB: Item should be available form context cache - should // not incur a performance hit here Item item = itemService.find(ctx, event.getSubjectID()); Collection coll = item.getOwningCollection(); - if (coll != null) - { + if (coll != null) { id2check = coll.getHandle(); } } + boolean onList = idFilter.contains(id2check); return idExclude ? ! onList : onList; } @@ -314,44 +305,34 @@ private boolean acceptId(String id, Event event, Context ctx) throws SQLExceptio * @param event event that was triggered * @throws Exception */ - private void deleteEvent(Context ctx, String id, Event event) throws Exception - { + private void deleteEvent(Context ctx, String id, Event event) throws Exception { int type = event.getEventType(); - if (DELETE == type) - { + if (DELETE == type) { // either marks start of new deletion or a member of enclosing one - if (delObjId == null) - { + if (delObjId == null) { //Start of a new deletion delObjId = id; - } - else - { + } else { // just add to list of deleted members delMemIds.add(id); } - } - else if (REMOVE == type) - { + } else if (REMOVE == type) { // either marks end of current deletion or is member of // enclosing one: ignore if latter - if (delObjId.equals(id)) - { + if (delObjId.equals(id)) { // determine owner and write out deletion catalog - if (Constants.COLLECTION == event.getSubjectType()) - { + if (Constants.COLLECTION == event.getSubjectType()) { // my owner is a collection Collection ownColl = collectionService.find(ctx, event.getSubjectID()); delOwnerId = ownColl.getHandle(); - } - else if (Constants.COMMUNITY == event.getSubjectType()) - { + } else if (Constants.COMMUNITY == event.getSubjectType()) { // my owner is a community Community comm = communityService.find(ctx, event.getSubjectID()); delOwnerId = comm.getHandle(); } + processDelete(ctx); - } + } } } @@ -359,9 +340,14 @@ else if (Constants.COMMUNITY == event.getSubjectType()) * Process a deletion event by recording a deletion catalog if configured */ private void processDelete(Context context) throws IOException { + if (repMan == null) { + log.error("The ReplicaManager failed to initialize earlier. Check the logs above."); + return; + } + // write out deletion catalog if defined if (catalogDeletes) { - //First, check if this object has an AIP in storage + // First, check if this object has an AIP in storage try { final String storageId = repMan.storageId(context, delObjId, archFmt); boolean found = repMan.objectExists(storeGroupName, storageId); @@ -376,7 +362,7 @@ private void processDelete(Context context) throws IOException { String catID = repMan.deletionCatalogId(delObjId, null); File packDir = repMan.stage(context, deleteGroupName, catID); File archive = packer.pack(packDir); - //System.out.println("delcat about to transfer"); + // System.out.println("delcat about to transfer"); repMan.transferObject(deleteGroupName, archive); } } catch (AuthorizeException | SQLException e) { @@ -395,37 +381,27 @@ private void processDelete(Context context) throws IOException { * @param filterName the name of the textual filter file * @return true if filter file was loaded successfully, false otherwise */ - private boolean loadIdFilter(String filterName) - { + private boolean loadIdFilter(String filterName) { File filterFile = new File(configurationService.getProperty("replicate.base.dir"), filterName); - if (filterFile.exists()) - { + if (filterFile.exists()) { idFilter = new ArrayList(); BufferedReader reader = null; - try - { + try { reader = new BufferedReader(new FileReader(filterFile)); String id = null; - while((id = reader.readLine()) != null) - { + while ((id = reader.readLine()) != null) { idFilter.add(id); } return true; - } - catch (IOException ioE) - { - //log.error("Unable to read filter file '" + filterName + "'"); + } catch (IOException ioE) { + // log.error("Unable to read filter file '" + filterName + "'"); idFilter = null; - } - finally - { + } finally { if (reader != null) { - try - { + try { reader.close(); - } - catch (IOException ioE) - { + } catch (IOException ioE) { + // ignore exception } } } @@ -442,15 +418,11 @@ private boolean loadIdFilter(String filterName) * @param tasks Tasks to be performed * @param id Object for which the tasks should be performed. */ - private void mapId(Map> map, List tasks, String id) - { - if (tasks != null) - { - for (String task : tasks) - { + private void mapId(Map> map, List tasks, String id) { + if (tasks != null) { + for (String task : tasks) { Set ids = map.get(task); - if (ids == null) - { + if (ids == null) { ids = new HashSet(); map.put(task, ids); } @@ -464,71 +436,50 @@ private void mapId(Map> map, List tasks, String id) * is in the 'replicate.cfg' file. * @param propName property name */ - private void parseTasks(String propName) - { + private void parseTasks(String propName) { String taskStr = configurationService.getProperty("replicate.consumer.tasks." + propName); - if (taskStr == null || taskStr.length() == 0) - { + if (taskStr == null || taskStr.isEmpty()) { return; } - for (String task : taskStr.split(",")) - { + for (String task : taskStr.split(",")) { task = task.trim(); - //If the task in question does NOT end in "+p", + // If the task in question does NOT end in "+p", // then it should be queued for later processing - if (! task.endsWith("+p")) - { - if ("add".equals(propName)) - { - if (addQTasks == null) - { + if (! task.endsWith("+p")) { + if ("add".equals(propName)) { + if (addQTasks == null) { addQTasks = new ArrayList(); } addQTasks.add(task); - } - else if ("mod".equals(propName)) - { - if (modQTasks == null) - { + } else if ("mod".equals(propName)) { + if (modQTasks == null) { modQTasks = new ArrayList(); } modQTasks.add(task); - } - else if ("del".equals(propName)) - { - if (delTasks == null) - { + } else if ("del".equals(propName)) { + if (delTasks == null) { delTasks = new ArrayList(); } delTasks.add(task); } - } - //Otherwise (if the task ends in "+p"), - // it should be added to the list of tasks to perform immediately - else - { + } else { + // Otherwise (if the task ends in "+p"), + // it should be added to the list of tasks to perform immediately + String sTask = task.substring(0, task.lastIndexOf("+p")); - if ("add".equals(propName)) - { - if (addPTasks == null) - { + if ("add".equals(propName)) { + if (addPTasks == null) { addPTasks = new ArrayList(); } addPTasks.add(sTask); - } - else if ("mod".equals(propName)) - { - if (modPTasks == null) - { + } else if ("mod".equals(propName)) { + if (modPTasks == null) { modPTasks = new ArrayList(); } addPTasks.add(sTask); - } - else if ("del".equals(propName)) - { + } else if ("del".equals(propName)) { // just test for special case of deletion catalogs. - if ("catalog".equals(sTask)) - { + if ("catalog".equals(sTask)) { catalogDeletes = true; } } diff --git a/src/main/java/org/dspace/ctask/replicate/BagItRestoreFromAIP.java b/src/main/java/org/dspace/ctask/replicate/BagItRestoreFromAIP.java index aca07487..1dfb0a08 100644 --- a/src/main/java/org/dspace/ctask/replicate/BagItRestoreFromAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/BagItRestoreFromAIP.java @@ -63,7 +63,7 @@ public class BagItRestoreFromAIP extends AbstractCurationTask { // Group where all AIPs are stored private String storeGroupName; - + // Group where object deletion catalog/records are stored private String deleteGroupName; @@ -79,7 +79,7 @@ public void init(Curator curator, String taskId) throws IOException { storeGroupName = configurationService.getProperty("replicate.group.aip.name"); archFmt = configurationService.getProperty("replicate.packer.archfmt"); } - + /** * Perform 'Recover From AIP' task on a particular object. If the {@code dso} is a {@link Site}, attempt to restore * the Site and child objects. Otherwise this method returns an exception. @@ -136,6 +136,7 @@ public int perform(final DSpaceObject dso) throws IOException { @Override public int perform(Context ctx, String id) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); + // first we locate the deletion catalog for this object String catId = repMan.deletionCatalogId(id, archFmt); File catArchive = repMan.fetchObject(ctx, deleteGroupName, catId); @@ -203,7 +204,7 @@ private void recover(Context ctx, ReplicaManager repMan, String id) throws IOExc /** * Recover a DSpace Item from a particular AIP package file * @param ctx current DSpace context - * @param archive AIP package file + * @param archive AIP package file * @param objId identifier of object we are restoring * @param props properties which control how item is restored * @throws IOException if IO error @@ -241,7 +242,7 @@ private void recoverItem(Context ctx, File archive, String objId, Properties pro /** * Recover a DSpace Collection from a particular AIP package file * @param ctx current DSpace context - * @param archive AIP package file + * @param archive AIP package file * @param collId identifier of collection we are restoring * @param commId identifier of parent community for this collection * @throws IOException if IO error @@ -268,7 +269,7 @@ private void recoverCollection(Context ctx, File archive, String collId, String /** * Recover a DSpace Community from a particular AIP package file * @param ctx current DSpace context - * @param archive AIP package file + * @param archive AIP package file * @param commId identifier of community we are restoring * @param parentId identifier of parent community (if any) for community * @throws IOException if IO error diff --git a/src/main/java/org/dspace/ctask/replicate/CompareWithAIP.java b/src/main/java/org/dspace/ctask/replicate/CompareWithAIP.java index 0b26a794..1be86f4d 100644 --- a/src/main/java/org/dspace/ctask/replicate/CompareWithAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/CompareWithAIP.java @@ -31,8 +31,8 @@ /** * CompareWithAIP task compares local repository values with the replica store * values. It can perform 2 types of comparison: first, an 'integrity' audit - * which compares the checksums of the local and remote zipped AIPs; second, a - * 'count' or enumerative audit that verifies that all child objects of a local + * which compares the checksums of the local and remote zipped AIPs; second, a + * 'count' or enumerative audit that verifies that all child objects of a local * container have corresponding replicas in the remote store. *

* The reason it performs two checks is for performance purposes. We'd rather @@ -49,13 +49,12 @@ * * @author richardrodgers */ -@Suspendable(invoked=Curator.Invoked.INTERACTIVE) -public class CompareWithAIP extends AbstractCurationTask -{ +@Suspendable(invoked = Curator.Invoked.INTERACTIVE) +public class CompareWithAIP extends AbstractCurationTask { private String archFmt; private int status = Curator.CURATE_UNSET; private String result = null; - + // Group where all AIPs are stored private String storeGroupName; @@ -73,21 +72,18 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); String id = dso.getHandle(); status = Curator.CURATE_SUCCESS; result = "Checksums of local and remote agree"; - try - { + try { Context context = Curator.curationContext(); String objId = repMan.storageId(context, id, archFmt); Packer packer = PackerFactory.instance(context, dso); - //First, make sure this object has an AIP in remote storage - if(checkReplica(context, repMan, dso)) - { - // generate an archive and calculate it's checksum + // First, make sure this object has an AIP in remote storage + if (checkReplica(context, repMan, dso)) { + // generate an archive and calculate its checksum File packDir = repMan.stage(context, storeGroupName, id); File archive = packer.pack(packDir); String chkSum = Utils.checksum(archive, "MD5"); @@ -96,33 +92,27 @@ public int perform(DSpaceObject dso) throws IOException // compare with replica String repChkSum = repMan.objectAttribute(storeGroupName, objId, "checksum"); - if (! chkSum.equals(repChkSum)) - { + if (! chkSum.equals(repChkSum)) { report("Local and remote checksums differ for: " + id); report("Local: " + chkSum + " replica: " + repChkSum); result = "Checksums of local and remote differ for: " + id; status = Curator.CURATE_FAIL; - } - else - { + } else { report("Local and remote checksums agree for: " + id); } + // if a container, also perform an extent (count) audit - i.e. // does replica store have replicas for each object in container? - if (Curator.isContainer(dso) || dso.getType() == Constants.SITE) - { + if (Curator.isContainer(dso) || dso.getType() == Constants.SITE) { auditExtent(context, repMan, dso); } } + setResult(result); return status; - } - catch (AuthorizeException authE) - { + } catch (AuthorizeException authE) { throw new IOException(authE); - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE); } } @@ -139,37 +129,30 @@ public int perform(DSpaceObject dso) throws IOException * @throws IOException if I/O error * @throws SQLException if database error */ - private void auditExtent(Context context, ReplicaManager repMan, DSpaceObject dso) throws IOException, SQLException - { + private void auditExtent(Context context, ReplicaManager repMan, DSpaceObject dso) + throws IOException, SQLException { int type = dso.getType(); - - //If container is a Collection, make sure all Items have AIPs in remote storage - if (Constants.COLLECTION == type) - { + + // If container is a Collection, make sure all Items have AIPs in remote storage + if (Constants.COLLECTION == type) { Collection coll = (Collection)dso; Iterator iter = itemService.findByCollection(context, coll); - while (iter.hasNext()) - { + while (iter.hasNext()) { checkReplica(context, repMan, iter.next()); } - } //If Community, make sure all Sub-Communities/Collections have AIPs in remote storage - else if (Constants.COMMUNITY == type) - { + } else if (Constants.COMMUNITY == type) { + // If Community, make sure all Sub-Communities/Collections have AIPs in remote storage Community comm = (Community)dso; - for (Community subcomm : comm.getSubcommunities()) - { + for (Community subcomm : comm.getSubcommunities()) { checkReplica(context, repMan, subcomm); } - for (Collection coll : comm.getCollections()) - { + for (Collection coll : comm.getCollections()) { checkReplica(context, repMan, coll); } - } //if Site, check to see all Top-Level Communities have an AIP in remote storage - else if (Constants.SITE == type) - { + } else if (Constants.SITE == type) { + // If Site, check to see all Top-Level Communities have an AIP in remote storage List topComm = communityService.findAllTop(context); - for (Community comm : topComm) - { + for (Community comm : topComm) { checkReplica(context, repMan, comm); } } @@ -184,19 +167,17 @@ else if (Constants.SITE == type) * @return true if replica exists, false otherwise * @throws IOException if I/O error */ - private boolean checkReplica(Context context, ReplicaManager repMan, DSpaceObject dso) throws IOException - { - String objId = repMan.storageId(context, dso.getHandle(), archFmt); + private boolean checkReplica(Context context, ReplicaManager repMan, DSpaceObject dso) throws IOException { + String objId = repMan.storageId(context, dso.getHandle(), archFmt); - if (! repMan.objectExists(storeGroupName, objId)) - { - String msg = "Missing replica for: " + dso.getHandle(); - report(msg); - result = msg; - status = Curator.CURATE_FAIL; - return false; - } - else - return true; + if (!repMan.objectExists(storeGroupName, objId)) { + String msg = "Missing replica for: " + dso.getHandle(); + report(msg); + result = msg; + status = Curator.CURATE_FAIL; + return false; + } else { + return true; + } } } diff --git a/src/main/java/org/dspace/ctask/replicate/EstimateAIPSize.java b/src/main/java/org/dspace/ctask/replicate/EstimateAIPSize.java index 3292b260..c6bc7c30 100644 --- a/src/main/java/org/dspace/ctask/replicate/EstimateAIPSize.java +++ b/src/main/java/org/dspace/ctask/replicate/EstimateAIPSize.java @@ -31,12 +31,10 @@ * @see TransmitAIP */ @Distributive -public class EstimateAIPSize extends AbstractCurationTask -{ +public class EstimateAIPSize extends AbstractCurationTask { @Override public int perform(DSpaceObject dso) throws IOException { - try - { + try { Packer packer = PackerFactory.instance(Curator.curationContext(), dso); // just report the size long size = packer.size(""); @@ -44,17 +42,15 @@ public int perform(DSpaceObject dso) throws IOException { ") estimated AIP size: " + scaledSize(size, 0); report(msg); setResult(scaledSize(size, 0)); - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE); } + return Curator.CURATE_SUCCESS; } - + String[] prefixes = { "", "kilo", "mega", "giga", "tera", "peta", "exa" }; - private String scaledSize(long size, int idx) - { + private String scaledSize(long size, int idx) { return (size < 1000L) ? size + " " + prefixes[idx] + "bytes" : scaledSize(size / 1000L, idx + 1); } diff --git a/src/main/java/org/dspace/ctask/replicate/FetchAIP.java b/src/main/java/org/dspace/ctask/replicate/FetchAIP.java index e7aca5bd..d3133e8c 100644 --- a/src/main/java/org/dspace/ctask/replicate/FetchAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/FetchAIP.java @@ -25,8 +25,7 @@ * @see TransmitAIP */ -public class FetchAIP extends AbstractCurationTask -{ +public class FetchAIP extends AbstractCurationTask { private String archFmt; private String baseFolder; @@ -49,18 +48,14 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { - if(dso!=null) - { + public int perform(DSpaceObject dso) throws IOException { + if (dso != null) { try { return perform(Curator.curationContext(), dso.getHandle()); } catch (SQLException e) { throw new IOException(e); } - } - else - { + } else { String result = "DSpace Object not found!"; report(result); setResult(result); @@ -77,16 +72,19 @@ public int perform(DSpaceObject dso) throws IOException * @throws IOException if I/O error */ @Override - public int perform(Context ctx, String id) throws IOException - { + public int perform(Context ctx, String id) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); String objId = repMan.storageId(ctx, id, archFmt); File archive = repMan.fetchObject(ctx, storeGroupName, objId); + boolean found = archive != null; String result = "AIP for object: " + id + " located : " + found + "."; - if(found) + + if (found) { result += " AIP file downloaded to '" + baseFolder + "/" + storeGroupName + "/" + objId + "'"; + } + report(result); setResult(result); return found ? Curator.CURATE_SUCCESS : Curator.CURATE_FAIL; diff --git a/src/main/java/org/dspace/ctask/replicate/FilteredFileTaskQueue.java b/src/main/java/org/dspace/ctask/replicate/FilteredFileTaskQueue.java index b0809e66..dad69872 100644 --- a/src/main/java/org/dspace/ctask/replicate/FilteredFileTaskQueue.java +++ b/src/main/java/org/dspace/ctask/replicate/FilteredFileTaskQueue.java @@ -33,18 +33,16 @@ * Only the first TWO entries will be returned by "dequeue()", as entries #3 * and #4 would be considered duplicates of entry #1. *

- * This FilteredFileTaskQueue is extremely useful to Replication Tasks, as it + * This FilteredFileTaskQueue is extremely useful to Replication Tasks, as it * ensures that AIPs are not (re-)generated multiple times when the queue * is actually processed. (NOTE however that some of the Replication store plugins * avoid duplicate transfers by ensuring Checksums differ before transferring) * * @author Tim Donohue */ -public class FilteredFileTaskQueue extends FileTaskQueue -{ +public class FilteredFileTaskQueue extends FileTaskQueue { private static Logger log = LogManager.getLogger(); - /** * Returns the set of UNIQUE task entries from the named queue. Any duplicate * task entries in the queue are ignored. The operation locks @@ -62,12 +60,11 @@ public class FilteredFileTaskQueue extends FileTaskQueue */ @Override public synchronized Set dequeue(String queueName, long ticket) - throws IOException - { - //Dequeue our list of tasks (which may include duplicates) + throws IOException { + // Dequeue our list of tasks (which may include duplicates) Set entrySet = super.dequeue(queueName, ticket); - //Filter out any duplicate entries in the task list + // Filter out any duplicate entries in the task list filterDuplicates(entrySet); return entrySet; @@ -78,25 +75,22 @@ public synchronized Set dequeue(String queueName, long ticket) * A duplicate entry is one that references the same object and the same task(s) * @param entries initial set of entries */ - private void filterDuplicates(Set entries) - { - //create filteredSet as a LinkedHashSet in order to maintain existing order of queue + private void filterDuplicates(Set entries) { + // create filteredSet as a LinkedHashSet in order to maintain existing order of queue Set filteredSet = new LinkedHashSet(); // Add all our TaskQueueEntries to our "filteredSet". - // This will filter out any duplicates automatically + // This will filter out any duplicates automatically // (see UniqueTaskQueueEntry.equals() below). Iterator entryIter = entries.iterator(); - while (entryIter.hasNext()) - { + while (entryIter.hasNext()) { filteredSet.add(new UniqueTaskQueueEntry(entryIter.next())); } // Now overwrite our initial entry set with the filtered list of entries entries.clear(); Iterator filterIter = filteredSet.iterator(); - while (filterIter.hasNext()) - { + while (filterIter.hasNext()) { entries.add(filterIter.next().getTaskQueueEntry()); } } @@ -108,19 +102,16 @@ private void filterDuplicates(Set entries) * TaskQueueEntry (not allowed, as it's "final"), or have a similar * TaskQueueEntry.equals() method. */ - private class UniqueTaskQueueEntry - { + private class UniqueTaskQueueEntry { private final TaskQueueEntry entry; private final String tasks; private final String objId; - public UniqueTaskQueueEntry(TaskQueueEntry entry) - { + public UniqueTaskQueueEntry(TaskQueueEntry entry) { this.entry = entry; List taskNames = entry.getTaskNames(); StringBuilder sb = new StringBuilder(); - for (String tName : taskNames) - { + for (String tName : taskNames) { sb.append(tName).append(","); } this.tasks = sb.substring(0, sb.length() - 1); @@ -131,12 +122,10 @@ public UniqueTaskQueueEntry(TaskQueueEntry entry) * Get the TaskQueueEntry object that was used to generate the TaskQueueEntryFilter * @return TaskQueueEntry object */ - public TaskQueueEntry getTaskQueueEntry() - { + public TaskQueueEntry getTaskQueueEntry() { return entry; } - /** * Return true if this object equals obj, false otherwise. * @@ -144,22 +133,20 @@ public TaskQueueEntry getTaskQueueEntry() * @return true if TaskQueueEntryFilter objects are equal */ @Override - public boolean equals(Object obj) - { - if (obj == null) - { + public boolean equals(Object obj) { + if (obj == null) { return false; } - if (getClass() != obj.getClass()) - { + + if (getClass() != obj.getClass()) { return false; } + final UniqueTaskQueueEntry other = (UniqueTaskQueueEntry) obj; // two task entries are considered "equal" if they refer to the // same object and same list of tasks if (this.tasks.equalsIgnoreCase(other.tasks) && - this.objId.equalsIgnoreCase(other.objId)) - { + this.objId.equalsIgnoreCase(other.objId)) { return true; } diff --git a/src/main/java/org/dspace/ctask/replicate/METSReplicateConsumer.java b/src/main/java/org/dspace/ctask/replicate/METSReplicateConsumer.java index 302fb3b0..5ccbf47b 100644 --- a/src/main/java/org/dspace/ctask/replicate/METSReplicateConsumer.java +++ b/src/main/java/org/dspace/ctask/replicate/METSReplicateConsumer.java @@ -122,21 +122,26 @@ public class METSReplicateConsumer implements Consumer { private final String deleteGroupName = configurationService.getProperty("replicate.group.delete.name"); @Override - public void initialize() throws Exception - { - repMan = ReplicaManager.instance(); + public void initialize() throws Exception { + try { + repMan = ReplicaManager.instance(); + } catch (IOException ioE) { + // The ReplicaManager attempts to initialize the ObjectStore specified in the configuration. + log.error("Unable to initialize the ReplicaManager. ", ioE); + } + taskQueue = (TaskQueue) pluginService.getSinglePlugin(TaskQueue.class); queueName = configurationService.getProperty("replicate.consumer.queue"); + // look for and load any idFilter files - excludes trump includes // An "idFilter" is an actual textual file named "exclude" or "include" // which contains a list of handles to filter from the Consumer - if (! loadIdFilter("exclude")) - { - if (loadIdFilter("include")) - { + if (! loadIdFilter("exclude")) { + if (loadIdFilter("include")) { idExclude = false; } } + taskQMap = new HashMap>(); taskPMap = new HashMap>(); parseTasks("add"); @@ -162,44 +167,39 @@ public void initialize() throws Exception * @throws Exception if error */ @Override - public void consume(Context ctx, Event event) throws Exception - { + public void consume(Context ctx, Event event) throws Exception { int evType = event.getEventType(); int subjType = event.getSubjectType(); - //In this situation the "id" is actually the Object Handle + + // In this situation the "id" is actually the Object Handle String id = null; //Special processing specific to Group & EPerson events - if(subjType==Constants.GROUP || subjType==Constants.EPERSON) - { + if (subjType == Constants.GROUP || subjType == Constants.EPERSON) { // ANY changes to a Group/EPerson are essentially modifications // to the DSpace System (Site), as they are site-wide changes Site site = siteService.findSite(ctx); id = site == null ? null : site.getHandle(); + // make sure we are supposed to process this object - if (acceptId(id, event, ctx)) - { + if (acceptId(id, event, ctx)) { // add it to the master lists of modified objects // for which we need to perform tasks mapId(taskQMap, modQTasks, id); mapId(taskPMap, modPTasks, id); } - } - else // process all other object types - { - switch (evType) - { - //ADD = Adding an object to a container or group + } else { + // process all other object types + switch (evType) { + // ADD = Adding an object to a container or group case ADD: - //If mapping/adding an Item to a Collection - if(subjType==Constants.COLLECTION) - { - //First, get Handle of collection that was modified + // If mapping/adding an Item to a Collection + if (subjType == Constants.COLLECTION) { + // First, get Handle of collection that was modified id = event.getSubject(ctx).getHandle(); // make sure we are supposed to process this Collection - if (acceptId(id, event, ctx)) - { + if (acceptId(id, event, ctx)) { // add Collection to the master lists of modified objects // for which we need to perform tasks mapId(taskQMap, modQTasks, id); @@ -214,21 +214,19 @@ public void consume(Context ctx, Event event) throws Exception mapId(taskPMap, modPTasks, id); } } - //IGNORE all other "ADD" events. Currently it's not possible to map - //Collections or SubCommunities to multiple parents. - break; - case CREATE: //CREATE = Create a new object. - case INSTALL: //INSTALL = Install an object (exits workflow/workspace). Only used for Items. + // IGNORE all other "ADD" events. Currently it's not possible to map + // Collections or SubCommunities to multiple parents. + break; + case CREATE: // CREATE = Create a new object. + case INSTALL: // INSTALL = Install an object (exits workflow/workspace). Only used for Items. // For CREATE & INSTALL, the Handle of object being created is found in Event Detail id = event.getDetail(); // if NOT (Create & Item) // (i.e. We don't want to replicate items UNTIL they are Installed) - if (!(subjType == Constants.ITEM && evType == CREATE)) - { - if (acceptId(id, event, ctx)) - { + if (!(subjType == Constants.ITEM && evType == CREATE)) { + if (acceptId(id, event, ctx)) { // add it to the master lists of added/new objects // for which we need to perform tasks mapId(taskQMap, addQTasks, id); @@ -237,14 +235,13 @@ public void consume(Context ctx, Event event) throws Exception // get parent of this newly created object & mark it as modified DSpaceObject subject = event.getSubject(ctx); - DSpaceObject parent = ContentServiceFactory.getInstance().getDSpaceObjectService(subject).getParentObject(ctx, subject); - if(parent!=null) - { + DSpaceObject parent = ContentServiceFactory.getInstance() + .getDSpaceObjectService(subject).getParentObject(ctx, subject); + + if (parent != null) { id = parent.getHandle(); - if(id != null) - { - if (acceptId(id, event, ctx)) - { + if (id != null) { + if (acceptId(id, event, ctx)) { // add it to the master lists of modified objects // for which we need to perform tasks mapId(taskQMap, modQTasks, id); @@ -254,12 +251,10 @@ public void consume(Context ctx, Event event) throws Exception } } break; - - case MODIFY: //MODIFY = modify an object - case MODIFY_METADATA: //MODIFY_METADATA = just modify an object's metadata + case MODIFY: // MODIFY = modify an object + case MODIFY_METADATA: // MODIFY_METADATA = just modify an object's metadata // If subject of event is null, this means the object was likely deleted - if (event.getSubject(ctx)==null) - { + if (event.getSubject(ctx) == null) { log.warn(event.getEventTypeAsString() + " event, could not get object for " + event.getSubjectTypeAsString() + " id=" + String.valueOf(event.getSubjectID()) @@ -267,16 +262,14 @@ public void consume(Context ctx, Event event) throws Exception break; } - //For MODIFY events, the Handle of modified object needs to be obtained from the Subject + // For MODIFY events, the Handle of modified object needs to be obtained from the Subject id = event.getSubject(ctx).getHandle(); // make sure handle resolves - these could be events // for a newly created item that hasn't been assigned a handle - if (id != null) - { + if (id != null) { // make sure we are supposed to process this object - if (acceptId(id, event, ctx)) - { + if (acceptId(id, event, ctx)) { // add it to the master lists of modified objects // for which we need to perform tasks mapId(taskQMap, modQTasks, id); @@ -284,58 +277,51 @@ public void consume(Context ctx, Event event) throws Exception } } break; - case REMOVE: //REMOVE = Remove an object from a container or group case DELETE: //DELETE = Delete an object (actually destroy it) // For REMOVE & DELETE, the Handle of object being deleted is found in Event Detail id = event.getDetail(); // make sure we are supposed to process this object - if (acceptId(id, event, ctx)) - { // analyze & process the deletion/removal event + if (acceptId(id, event, ctx)) { + // analyze & process the deletion/removal event deleteEvent(ctx, id, event); } - break; default: break; - }//end switch - }//end if + } + } } @Override - public void end(Context ctx) throws Exception - { + public void end(Context ctx) throws Exception { // if there are any pending objectIds, pass them to the curation // system to queue for later processing, or perform immediately EPerson ep = ctx.getCurrentUser(); String name = (ep != null) ? ep.getName() : "unknown"; long stamp = System.currentTimeMillis(); + // first the queueables Set entrySet = new HashSet(); - if (taskQMap.size() > 0) - { + if (!taskQMap.isEmpty()) { List taskList = new ArrayList(); - for (String task : taskQMap.keySet()) - { + for (String task : taskQMap.keySet()) { taskList.add(task); - for (String id : taskQMap.get(task)) - { + for (String id : taskQMap.get(task)) { entrySet.add(new TaskQueueEntry(name, stamp, taskList, id)); } taskList.clear(); } taskQMap.clear(); } + // now the performables - if (taskPMap.size() > 0) - { + if (!taskPMap.isEmpty()) { Curator curator = new Curator(); - for (String task : taskPMap.keySet()) - { + for (String task : taskPMap.keySet()) { curator.addTask(task); - for (String id : taskQMap.get(task)) - { + for (String id : taskQMap.get(task)) { curator.curate(ctx, id); } curator.clear(); @@ -344,23 +330,20 @@ public void end(Context ctx) throws Exception } // if there any uncommitted deletions, record them now - if (delObjId != null) - { - if (delTasks != null) - { + if (delObjId != null) { + if (delTasks != null) { entrySet.add(new TaskQueueEntry(name, stamp, delTasks, delObjId)); } processDelete(ctx); } - if (entrySet.size() > 0) - { + + if (!entrySet.isEmpty()) { taskQueue.enqueue(queueName, entrySet); } } @Override - public void finish(Context ctx) throws Exception - { + public void finish(Context ctx) throws Exception { // no-op } @@ -376,27 +359,25 @@ public void finish(Context ctx) throws Exception * @return true if this consumer should process this object event, false if it should not * @throws SQLException if database error occurs */ - private boolean acceptId(String id, Event event, Context ctx) throws SQLException - { + private boolean acceptId(String id, Event event, Context ctx) throws SQLException { // always accept if not filtering - if (idFilter == null) - { + if (idFilter == null) { return true; } + // filter supports only container ids - so if id is for an item, // find its owning collection String id2check = id; - if (event.getSubjectType() == Constants.ITEM) - { + if (event.getSubjectType() == Constants.ITEM) { // NB: Item should be available form context cache - should // not incur a performance hit here Item item = itemService.find(ctx, event.getSubjectID()); Collection coll = item.getOwningCollection(); - if (coll != null) - { + if (coll != null) { id2check = coll.getHandle(); } } + boolean onList = idFilter.contains(id2check); return idExclude ? ! onList : onList; } @@ -410,38 +391,27 @@ private boolean acceptId(String id, Event event, Context ctx) throws SQLExceptio * @param event event that was triggered * @throws Exception if error */ - private void deleteEvent(Context ctx, String id, Event event) throws Exception - { + private void deleteEvent(Context ctx, String id, Event event) throws Exception { int type = event.getEventType(); - if (DELETE == type) - { + if (DELETE == type) { // either marks start of new deletion or a member of enclosing one - if (delObjId == null) - { - //Start of a new deletion + if (delObjId == null) { + // Start of a new deletion delObjId = id; - } - else - { + } else { // just add to list of deleted members delMemIds.add(id); } - } - else if (REMOVE == type) - { + } else if (REMOVE == type) { // either marks end of current deletion or is member of // enclosing one: ignore if latter - if (event.getDetail().equals(id) || (delObjId != null && delObjId.equals(id))) - { + if (event.getDetail().equals(id) || (delObjId != null && delObjId.equals(id))) { // determine owner and write out deletion catalog - if (Constants.COLLECTION == event.getSubjectType()) - { + if (Constants.COLLECTION == event.getSubjectType()) { // my owner is a collection Collection ownColl = collectionService.find(ctx, event.getSubjectID()); delOwnerId = ownColl.getHandle(); - } - else if (Constants.COMMUNITY == event.getSubjectType()) - { + } else if (Constants.COMMUNITY == event.getSubjectType()) { // my owner is a community Community comm = communityService.find(ctx, event.getSubjectID()); delOwnerId = comm.getHandle(); @@ -449,10 +419,8 @@ else if (Constants.COMMUNITY == event.getSubjectType()) // If the parent/owner was found, mark that parent as having been modified // (This ensures that a fresh AIP will be generated for the parent object) - if(delOwnerId != null) - { - if (acceptId(delOwnerId, event, ctx)) - { + if (delOwnerId != null) { + if (acceptId(delOwnerId, event, ctx)) { // add parent to the master lists of modified objects // for which we need to perform tasks mapId(taskQMap, modQTasks, delOwnerId); @@ -460,32 +428,33 @@ else if (Constants.COMMUNITY == event.getSubjectType()) } } - //Record the deletion catalog for the deleted object (as needed) + // Record the deletion catalog for the deleted object (as needed) processDelete(ctx); - } + } } } /* * Process a deletion event by recording a deletion catalog if configured */ - private void processDelete(Context ctx) throws IOException - { + private void processDelete(Context ctx) throws IOException { + if (repMan == null) { + log.error("The ReplicaManager failed to initialize earlier. Check the logs above."); + return; + } + // write out deletion catalog if defined - if (catalogDeletes) - { - //First, check if this object has an AIP in storage + if (catalogDeletes) { + // First, check if this object has an AIP in storage boolean found = repMan.objectExists(storeGroupName, delObjId); // If the object has an AIP, then create a deletion catalog // If there's no AIP, then there's no need for a deletion // catalog as the object isn't backed up & cannot be restored! - if(found) - { + if (found) { //Create a deletion catalog (in BagIt format) of all deleted objects Packer packer = new CatalogPacker(ctx, delObjId, delOwnerId, delMemIds); - try - { + try { // Create a new deletion catalog (with default file extension / format) // and store it in the deletion group store String catID = repMan.deletionCatalogId(delObjId, null); @@ -493,17 +462,14 @@ private void processDelete(Context ctx) throws IOException File archive = packer.pack(packDir); // Create a deletion catalog in deletion archive location. repMan.transferObject(deleteGroupName, archive); - } - catch (AuthorizeException authE) - { + } catch (AuthorizeException authE) { throw new IOException(authE); - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE); } } } + // reset for next events delObjId = delOwnerId = null; delMemIds.clear(); @@ -516,41 +482,32 @@ private void processDelete(Context ctx) throws IOException * @param filterName the name of the textual filter file * @return true if filter file was loaded successfully, false otherwise */ - private boolean loadIdFilter(String filterName) - { + private boolean loadIdFilter(String filterName) { File filterFile = new File(configurationService.getProperty("replicate.base.dir"), filterName); - if (filterFile.exists()) - { + if (filterFile.exists()) { idFilter = new ArrayList(); BufferedReader reader = null; - try - { + try { reader = new BufferedReader(new FileReader(filterFile)); String id = null; - while((id = reader.readLine()) != null) - { + while ((id = reader.readLine()) != null) { idFilter.add(id); } return true; - } - catch (IOException ioE) - { - //log.error("Unable to read filter file '" + filterName + "'"); + } catch (IOException ioE) { + // log.error("Unable to read filter file '" + filterName + "'"); idFilter = null; - } - finally - { + } finally { if (reader != null) { - try - { + try { reader.close(); - } - catch (IOException ioE) - { + } catch (IOException ioE) { + // ignore exception } } } } + return false; } @@ -563,15 +520,11 @@ private boolean loadIdFilter(String filterName) * @param tasks Tasks to be performed * @param id Object for which the tasks should be performed. */ - private void mapId(Map> map, List tasks, String id) - { - if (tasks != null) - { - for (String task : tasks) - { + private void mapId(Map> map, List tasks, String id) { + if (tasks != null) { + for (String task : tasks) { Set ids = map.get(task); - if (ids == null) - { + if (ids == null) { ids = new HashSet(); map.put(task, ids); } @@ -585,76 +538,55 @@ private void mapId(Map> map, List tasks, String id) * is in the 'replicate.cfg' file. * @param propName property name */ - private void parseTasks(String propName) - { + private void parseTasks(String propName) { String taskStr = configurationService.getProperty("replicate.consumer.tasks." + propName); - if (taskStr == null || taskStr.length() == 0) - { + if (taskStr == null || taskStr.isEmpty()) { return; } - for (String task : taskStr.split(",")) - { + + for (String task : taskStr.split(",")) { task = task.trim(); + //If the task in question does NOT end in "+p", // then it should be queued for later processing - if (! task.endsWith("+p")) - { - if ("add".equals(propName)) - { - if (addQTasks == null) - { + if (!task.endsWith("+p")) { + if ("add".equals(propName)) { + if (addQTasks == null) { addQTasks = new ArrayList(); } addQTasks.add(task); - } - else if ("mod".equals(propName)) - { - if (modQTasks == null) - { + } else if ("mod".equals(propName)) { + if (modQTasks == null) { modQTasks = new ArrayList(); } modQTasks.add(task); - } - else if ("del".equals(propName)) - { - if (delTasks == null) - { + } else if ("del".equals(propName)) { + if (delTasks == null) { delTasks = new ArrayList(); } delTasks.add(task); } - } - //Otherwise (if the task ends in "+p"), - // it should be added to the list of tasks to perform immediately - else - { + } else { + // Otherwise (if the task ends in "+p"), + // it should be added to the list of tasks to perform immediately String sTask = task.substring(0, task.lastIndexOf("+p")); - if ("add".equals(propName)) - { - if (addPTasks == null) - { + if ("add".equals(propName)) { + if (addPTasks == null) { addPTasks = new ArrayList(); } addPTasks.add(sTask); - } - else if ("mod".equals(propName)) - { - if (modPTasks == null) - { + } else if ("mod".equals(propName)) { + if (modPTasks == null) { modPTasks = new ArrayList(); } addPTasks.add(sTask); - } - else if ("del".equals(propName)) - { + } else if ("del".equals(propName)) { // just test for special case of deletion catalogs. - if ("catalog".equals(sTask)) - { + if ("catalog".equals(sTask)) { catalogDeletes = true; } } } } } - } diff --git a/src/main/java/org/dspace/ctask/replicate/METSRestoreFromAIP.java b/src/main/java/org/dspace/ctask/replicate/METSRestoreFromAIP.java index 0bc7ded8..809e178a 100644 --- a/src/main/java/org/dspace/ctask/replicate/METSRestoreFromAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/METSRestoreFromAIP.java @@ -32,10 +32,9 @@ */ @Distributive @Mutative -public class METSRestoreFromAIP extends AbstractPackagerTask -{ +public class METSRestoreFromAIP extends AbstractPackagerTask { private Logger log = LogManager.getLogger(); - + private String archFmt; // Group where all AIPs are stored @@ -43,7 +42,7 @@ public class METSRestoreFromAIP extends AbstractPackagerTask // Group where object deletion catalog/records are stored private String deleteGroupName; - + // Name of module configuration file specific to METS based AIPs private final String metsModuleConfig = "replicate-mets"; @@ -54,8 +53,7 @@ public void init(Curator curator, String taskId) throws IOException { storeGroupName = configurationService.getProperty("replicate.group.aip.name"); deleteGroupName = configurationService.getProperty("replicate.group.delete.name"); } - - + /** * Perform the Restore/Replace task. *

@@ -67,30 +65,28 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(Context ctx, String id) throws IOException - { + public int perform(Context ctx, String id) throws IOException { String result = null; int status = Curator.CURATE_FAIL; - + ReplicaManager repMan = ReplicaManager.instance(); - - //Look for object in Replica Store + + // Look for object in Replica Store String objId = repMan.storageId(ctx, id, archFmt); File archive = repMan.fetchObject(ctx, storeGroupName, objId); - - if (archive != null) - { - //Load packaging options from replicate-mets.cfg configuration file + + if (archive != null) { + // Load packaging options from replicate-mets.cfg configuration file PackageParameters pkgParams = this.loadPackagerParameters(metsModuleConfig); - - //log that this task is starting (as this may be a large task) + + // log that this task is starting (as this may be a large task) log.info(getStartMsg(id, pkgParams)); - - //restore/replace object represented by this archive file - //(based on packaging params, this may also restore/replace all child objects too) + + // restore/replace object represented by this archive file + // (based on packaging params, this may also restore/replace all child objects too) restoreObject(ctx, repMan, archive, pkgParams); - //Check if a deletion catalog exists for this object + // Check if a deletion catalog exists for this object String catId = repMan.deletionCatalogId(id, archFmt); File catArchive = repMan.fetchObject(ctx, deleteGroupName, catId); if (catArchive != null) { @@ -99,44 +95,36 @@ public int perform(Context ctx, String id) throws IOException // remove from local cache as well catArchive.delete(); } - + result = getSuccessMsg(id, pkgParams); status = Curator.CURATE_SUCCESS; - } - else - { + } else { result = "Failed to update Object '" + id + "'. AIP could not be found in Replica Store."; } - + report(result); setResult(result); return status; } - - - + @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { int status = Curator.CURATE_FAIL; - try - { - //Get Context from current curation thread + try { + // Get Context from current curation thread Context ctx = Curator.curationContext(); status = perform(ctx, dso.getHandle()); - //Note: context will be committed/closed by Curator - } - catch(SQLException sqle) - { - throw new IOException(sqle); + // Note: context will be committed/closed by Curator + } catch (SQLException sqlE) { + throw new IOException(sqlE); } + return status; } - - + /** * Restores/Replaces a DSpace Object (along with possibly its child objects), - * based on an archive file in the Replica Filestore and the given + * based on an archive file in the Replica Filestore and the given * PackageParameters. * * @param context the context to use @@ -146,121 +134,109 @@ public int perform(DSpaceObject dso) throws IOException * @throws IOException if I/O error */ private void restoreObject(Context context, ReplicaManager repMan, File archive, PackageParameters pkgParams) - throws IOException - { - //Initialize a new METS-based packer, without an associated object + throws IOException { + // Initialize a new METS-based packer, without an associated object METSPacker packer = new METSPacker(context, archFmt); - - try - { - //unpack archival package & actually run the restore/replace, + + try { + // unpack archival package & actually run the restore/replace, // based on the current PackageParameters // This only restores/replaces a single object. packer.unpack(archive, pkgParams); // Remove the locally cached archive file - it is no longer needed. - if(archive.exists()) + if (archive.exists()) { archive.delete(); + } - //check if recursiveMode is enabled (restore/replace multiple objects) - if(pkgParams.recursiveModeEnabled()) - { - //See if this package refered to child packages, - //if so, we want to also replace those child objects + // check if recursiveMode is enabled (restore/replace multiple objects) + if (pkgParams.recursiveModeEnabled()) { + // See if this package refered to child packages, + // if so, we want to also replace those child objects List childPkgRefs = packer.getChildPackageRefs(); - if(childPkgRefs!=null && !childPkgRefs.isEmpty()) - { - for(String childRef : childPkgRefs) - { + if (childPkgRefs != null && !childPkgRefs.isEmpty()) { + for (String childRef : childPkgRefs) { File childArchive = repMan.fetchObject(context, storeGroupName, childRef); - if(childArchive!=null) - { - //recurse to restore/replace this child object (and all its children) + if (childArchive != null) { + // recurse to restore/replace this child object (and all its children) restoreObject(context, repMan, childArchive, pkgParams); - } - else - { + } else { throw new IOException("Archive " + childRef + " was not found in Replica Store"); } - } + } } } + } catch (AuthorizeException authE) { + throw new IOException(authE); + } catch (SQLException sqlE) { + throw new IOException(sqlE); } - catch(AuthorizeException authe) - { - throw new IOException(authe); - } - catch(SQLException sqle) - { - throw new IOException(sqle); - } - } - - + } + /** - * Return a human-friendly 'start processing' message based on the + * Return a human-friendly 'start processing' message based on the * actions performed (determined via PackageParameters). * * @param objId Object ID * @param pkgParams PackageParameters (used to determine actions) * @return human-friendly start message */ - private String getStartMsg(String objId, PackageParameters pkgParams) - { + private String getStartMsg(String objId, PackageParameters pkgParams) { String resultMsg = "Beginning "; - - //add action - if(pkgParams.replaceModeEnabled()) + + // add action + if (pkgParams.replaceModeEnabled()) { resultMsg += "replacement of "; - else if (pkgParams.keepExistingModeEnabled()) + } else if (pkgParams.keepExistingModeEnabled()) { resultMsg += "restoration (keep-existing mode) of "; - else + } else { resultMsg += "restoration of "; - - //add object info - resultMsg += "Object '" + objId +"' "; - - //is it recursive? - if(pkgParams.recursiveModeEnabled()) + } + + // add object info + resultMsg += "Object '" + objId + "' "; + + // is it recursive? + if (pkgParams.recursiveModeEnabled()) { resultMsg += "(and all child objects) "; - - //complete message; + } + + // complete message; resultMsg += "from AIP."; return resultMsg; - } - + /** - * Return a human-friendly success message based on the + * Return a human-friendly success message based on the * actions performed (determined via PackageParameters). * * @param objId Object ID * @param pkgParams PackageParameters (used to determine actions) * @return human-friendly result message */ - private String getSuccessMsg(String objId, PackageParameters pkgParams) - { + private String getSuccessMsg(String objId, PackageParameters pkgParams) { String resultMsg = "Successfully "; - - //add action - if(pkgParams.replaceModeEnabled()) + + // add action + if (pkgParams.replaceModeEnabled()) { resultMsg += "replaced "; - else if (pkgParams.keepExistingModeEnabled()) + } else if (pkgParams.keepExistingModeEnabled()) { resultMsg += "restored (keep-existing mode) "; - else + } else { resultMsg += "restored "; - - //add object info - resultMsg += "Object '" + objId +"' "; - - //is it recursive? - if(pkgParams.recursiveModeEnabled()) + } + + // add object info + resultMsg += "Object '" + objId + "' "; + + // is it recursive? + if (pkgParams.recursiveModeEnabled()) { resultMsg += "(and all child objects) "; - - //complete message; + } + + // complete message; resultMsg += "from AIP."; return resultMsg; } - } diff --git a/src/main/java/org/dspace/ctask/replicate/MoveToTrashSingleAIP.java b/src/main/java/org/dspace/ctask/replicate/MoveToTrashSingleAIP.java index 231c8b05..13f6ffd7 100644 --- a/src/main/java/org/dspace/ctask/replicate/MoveToTrashSingleAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/MoveToTrashSingleAIP.java @@ -36,8 +36,7 @@ * @author tdonohue */ @Distributive -public class MoveToTrashSingleAIP extends AbstractCurationTask -{ +public class MoveToTrashSingleAIP extends AbstractCurationTask { // Source and destination group where AIP will be moved to private String srcGroupName; private String destGroupName; @@ -63,18 +62,14 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { - if(dso!=null) - { + public int perform(DSpaceObject dso) throws IOException { + if (dso != null) { try { return perform(Curator.curationContext(), dso.getHandle()); } catch (SQLException e) { throw new IOException(e); } - } - else - { + } else { String result = "DSpace Object not specified!"; report(result); setResult(result); @@ -92,16 +87,19 @@ public int perform(DSpaceObject dso) throws IOException * @throws IOException if I/O error */ @Override - public int perform(Context ctx, String id) throws IOException - { + public int perform(Context ctx, String id) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); String objId = repMan.storageId(ctx, id, archFmt); boolean success = repMan.moveObject(srcGroupName, destGroupName, objId); - String result = "AIP for object: " + id + " could NOT be moved from: " + srcGroupName + " to : " + destGroupName + "."; - if(success) + String result = "AIP for object: " + id + " could NOT be moved from: " + srcGroupName + " to : " + + destGroupName + "."; + + if (success) { result = "AIP for object: " + id + " moved from: " + srcGroupName + " to : " + destGroupName + "."; + } + report(result); setResult(result); diff --git a/src/main/java/org/dspace/ctask/replicate/ObjectStore.java b/src/main/java/org/dspace/ctask/replicate/ObjectStore.java index 98ebde64..a53d321b 100644 --- a/src/main/java/org/dspace/ctask/replicate/ObjectStore.java +++ b/src/main/java/org/dspace/ctask/replicate/ObjectStore.java @@ -56,7 +56,6 @@ public interface ObjectStore { * @throws IOException if I/O error */ long fetchObject(String group, String id, File file) throws IOException; - /** * Transfers a copy of this file to the object store @@ -78,7 +77,7 @@ public interface ObjectStore { * @throws IOException if I/O error */ long removeObject(String group, String id) throws IOException; - + /** * Moves the passed object from one storage group to another. * diff --git a/src/main/java/org/dspace/ctask/replicate/Odometer.java b/src/main/java/org/dspace/ctask/replicate/Odometer.java index 6eb20e9b..d3e1ec0a 100644 --- a/src/main/java/org/dspace/ctask/replicate/Odometer.java +++ b/src/main/java/org/dspace/ctask/replicate/Odometer.java @@ -21,7 +21,7 @@ * usage. This can assist the consumer of the service to monitor it's cost, * inter alia. *

- * The Odometer tracks basic statistics of replication activities: bytes uploaded, + * The Odometer tracks basic statistics of replication activities: bytes uploaded, * modified, count of objects, and external objectstore size. *

* See org.dspace.ctask.replicate.ReplicaManager for how the Odometer readings @@ -30,8 +30,7 @@ * @author richardrodgers * @see org.dspace.ctask.replicate.ReplicaManager */ -public class Odometer -{ +public class Odometer { // name of file private static final String ODO_NAME = "odometer"; // names of fixed properties @@ -47,75 +46,56 @@ public class Odometer // directory path private String dirPath = null; - Odometer(String dirPath, boolean readOnly) throws IOException - { + Odometer(String dirPath, boolean readOnly) throws IOException { this.readOnly = readOnly; this.dirPath = dirPath; odoProps = new Properties(); - try - { + try { File odoFile = new File(dirPath, ODO_NAME); - if (odoFile.exists()) - { - + if (odoFile.exists()) { InputStream in = null; - try - { + try { in = new FileInputStream(odoFile); odoProps.load(new FileInputStream(odoFile)); - } - finally - { - if (in != null) - { + } finally { + if (in != null) { in.close(); } } } - } - catch (FileNotFoundException fnfE) - { + } catch (FileNotFoundException fnfE) { throw new IOException(fnfE); } } - void save() throws IOException - { - if (! readOnly) - { + void save() throws IOException { + if (!readOnly) { odoProps.setProperty("modified", String.valueOf(System.currentTimeMillis())); File odoFile = new File(dirPath, ODO_NAME); OutputStream out = null; - try - { + try { out = new FileOutputStream(odoFile); odoProps.store(out, null); - } - finally - { - if (out != null) - { + } finally { + if (out != null) { out.close(); } } } } - void adjustProperty(String name, long adjustment) - { + void adjustProperty(String name, long adjustment) { long val = getProperty(name); setProperty(name, val + adjustment); } - void setProperty(String name, long value) - { + void setProperty(String name, long value) { odoProps.setProperty(name, String.valueOf(value)); } - - public long getProperty(String name) - { - String val = odoProps.getProperty(name); - long lval = val != null ? Long.valueOf(val) : 0L; - return lval; + + public long getProperty(String name) { + String val = odoProps.getProperty(name); + long lval = val != null ? Long.valueOf(val) : 0L; + return lval; } } diff --git a/src/main/java/org/dspace/ctask/replicate/ReadOdometer.java b/src/main/java/org/dspace/ctask/replicate/ReadOdometer.java index 7c299a99..933fd2d3 100644 --- a/src/main/java/org/dspace/ctask/replicate/ReadOdometer.java +++ b/src/main/java/org/dspace/ctask/replicate/ReadOdometer.java @@ -16,7 +16,7 @@ /** * ReadOdometer simply reads and displays the odometer data. Since this data - * is currently only maintained per site, the actual data object is ignored. + * is currently only maintained per site, the actual data object is ignored. *

* Odometer data is stored in base folder for the Replication Task Suite * (see 'base.dir' setting in 'replicate.cfg'). It is stored in a text file @@ -26,8 +26,7 @@ * @see Odometer */ @Distributive -public class ReadOdometer extends AbstractCurationTask -{ +public class ReadOdometer extends AbstractCurationTask { /** * Performs the "Read Odometer" task. * @param dso this param is ignored, as the odometer is sitewide @@ -35,8 +34,7 @@ public class ReadOdometer extends AbstractCurationTask * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); Odometer odometer = repMan.getOdometer(); StringBuilder sb = new StringBuilder(); @@ -44,15 +42,14 @@ public int perform(DSpaceObject dso) throws IOException sb.append("Size: ").append(scaledSize(odometer.getProperty("storesize"), 0)).append(", \n"); sb.append("Uploaded: ").append(scaledSize(odometer.getProperty("uploaded"), 0)).append(", \n"); sb.append("Downloaded: ").append(scaledSize(odometer.getProperty("downloaded"), 0)).append("\n"); - String msg = sb.toString(); + String msg = sb.toString(); report(msg); setResult(msg); return Curator.CURATE_SUCCESS; } - + String[] prefixes = { "", "kilo", "mega", "giga", "tera", "peta", "exa" }; - private String scaledSize(long size, int idx) - { + private String scaledSize(long size, int idx) { return (size < 1000L) ? size + " " + prefixes[idx] + "bytes" : scaledSize(size / 1000L, idx + 1); } diff --git a/src/main/java/org/dspace/ctask/replicate/RemoveAIP.java b/src/main/java/org/dspace/ctask/replicate/RemoveAIP.java index 0b9cec69..988b8b34 100644 --- a/src/main/java/org/dspace/ctask/replicate/RemoveAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/RemoveAIP.java @@ -37,12 +37,11 @@ */ @Distributive public class RemoveAIP extends AbstractCurationTask { - private String archFmt; // Group where all AIPs are stored private String storeGroupName; - + // Group where object deletion catalog/records are stored private String deleteGroupName; @@ -68,8 +67,7 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); try { remove(Curator.curationContext(), repMan, dso); @@ -90,22 +88,21 @@ public int perform(DSpaceObject dso) throws IOException * @throws IOException if I/O error * @throws SQLException if database error */ - private void remove(Context context, ReplicaManager repMan, DSpaceObject dso) throws IOException, SQLException - { - //Remove object from AIP storage + private void remove(Context context, ReplicaManager repMan, DSpaceObject dso) throws IOException, SQLException { + // Remove object from AIP storage String objId = repMan.storageId(context, dso.getHandle(), archFmt); repMan.removeObject(storeGroupName, objId); report("Removing AIP for: " + objId); - //If it is a Collection, also remove all Items from AIP storage + // If it is a Collection, also remove all Items from AIP storage if (dso instanceof Collection) { Collection coll = (Collection) dso; Iterator iter = itemService.findByCollection(context, coll); while (iter.hasNext()) { remove(context, repMan, iter.next()); } - } // else if it a Community, also remove all sub-communities, collections (and items) from AIP storage - else if (dso instanceof Community) { + } else if (dso instanceof Community) { + // else if it's a Community, also remove all sub-communities, collections (and items) from AIP storage Community comm = (Community) dso; for (Community subcomm : comm.getSubcommunities()) { remove(context, repMan, subcomm); @@ -113,8 +110,8 @@ else if (dso instanceof Community) { for (Collection coll : comm.getCollections()) { remove(context, repMan, coll); } - } //else if it is a Site object, remove all top-level communities (and everything else) from AIP storage - else if (dso instanceof Site) { + } else if (dso instanceof Site) { + // else if it's a Site object, remove all top-level communities (and everything else) from AIP storage List topCommunities = communityService.findAllTop(context); for (Community subcomm : topCommunities) { @@ -137,11 +134,10 @@ else if (dso instanceof Site) { * @throws IOException if I/O error */ @Override - public int perform(Context ctx, String id) throws IOException - { + public int perform(Context ctx, String id) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); - - //If the object is still in DSpace, call perform(dso) instead. + + // If the object is still in DSpace, call perform(dso) instead. DSpaceObject dso = dereference(ctx, id); if (dso != null) { return perform(dso); @@ -158,17 +154,19 @@ public int perform(Context ctx, String id) throws IOException if (catFile != null) { CatalogPacker cpack = new CatalogPacker(ctx, id); cpack.unpack(catFile); + // remove the object AIP itself String objId = repMan.storageId(ctx, id, archFmt); repMan.removeObject(storeGroupName, objId); report("Removing AIP for: " + objId); + // remove all member/child object's AIPs for (String mem : cpack.getMembers()) { String memId = repMan.storageId(ctx, mem, archFmt); repMan.removeObject(storeGroupName, memId); report("Removing AIP for: " + memId); } - + // remove local deletion catalog catFile.delete(); // remove remote deletion catalog @@ -176,10 +174,9 @@ public int perform(Context ctx, String id) throws IOException result = "AIP for '" + id + "' has been removed (along with any child object AIPs)"; status = Curator.CURATE_SUCCESS; - } - else - { - result = "Deletion record for '" + id + "' could not be found in Replica Store. Perhaps this object's AIP was already removed?"; + } else { + result = "Deletion record for '" + id + "' could not be found in Replica Store. Perhaps " + + "this object's AIP was already removed?"; } setResult(result); diff --git a/src/main/java/org/dspace/ctask/replicate/ReplicaManager.java b/src/main/java/org/dspace/ctask/replicate/ReplicaManager.java index e7ae72b8..604b5845 100644 --- a/src/main/java/org/dspace/ctask/replicate/ReplicaManager.java +++ b/src/main/java/org/dspace/ctask/replicate/ReplicaManager.java @@ -36,7 +36,6 @@ * @author richardrodgers */ public class ReplicaManager { - private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); private PluginService pluginService = CoreServiceFactory.getInstance().getPluginService(); private HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); @@ -64,54 +63,45 @@ public class ReplicaManager { private final String archFmt = configurationService.getProperty("replicate.packer.archfmt"); - private ReplicaManager() throws IOException - { + private ReplicaManager() throws IOException { objStore = (ObjectStore) pluginService.getSinglePlugin(ObjectStore.class); if (objStore == null) { log.error("No ObjectStore configured in 'replicate.cfg'!"); throw new IOException("No ObjectStore configured in 'replicate.cfg'!"); } - + objStore.init(); - + // create directory structures new File(repDir).mkdirs(); // load our odometer - writeable copy - try - { + try { odometer = new Odometer(repDir, false); - } - catch (IOException ioE) - { - //just log a warning - log.warn("Unable to read odometer file in '"+ repDir + "'", ioE); + } catch (IOException ioE) { + // just log a warning + log.warn("Unable to read odometer file in '" + repDir + "'", ioE); } } - public static synchronized ReplicaManager instance() throws IOException - { - if (instance == null) - { + public static synchronized ReplicaManager instance() throws IOException { + if (instance == null) { instance = new ReplicaManager(); } return instance; } - - public File stage(Context context, String group, String id) - { + + public File stage(Context context, String group, String id) { // ensure path exists File stageDir = new File(repDir + File.separator + group); - if (! stageDir.isDirectory()) - { + if (!stageDir.isDirectory()) { stageDir.mkdirs(); } return new File(stageDir, storageId(context, id, null)); } - - + /** - * Determine the Identifier of an object once it is placed - * in storage. This method ensures any special characters are + * Determine the Identifier of an object once it is placed + * in storage. This method ensures any special characters are * escaped. It also ensures all objects are named in a similar * manner once they are in a given store (so that they can similarly * be retrieved from storage using this same 'storageId'). @@ -121,84 +111,81 @@ public File stage(Context context, String group, String id) * @param fileExtension - file extension, if any (may be null) * @return reformatted storage ID for this object (including file extension) */ - public String storageId(Context context, String objId, String fileExtension) - { + public String storageId(Context context, String objId, String fileExtension) { // canonical handle notation bedevils file system semantics String storageId = objId.replaceAll("/", "-"); - + // add appropriate file extension, if needed - if(fileExtension!=null && !storageId.endsWith("." + fileExtension)) + if (fileExtension != null && !storageId.endsWith("." + fileExtension)) { storageId = storageId + "." + fileExtension; + } - // If 'packer.typeprefix' setting is 'true', + // If 'packer.typeprefix' setting is 'true', // then prefix the storageID with the DSpace Type (if it doesn't already have a prefix) - if(configurationService.getBooleanProperty("replicate.packer.typeprefix", true) && - !storageId.contains(typePrefixSeparator)) - { + if (configurationService.getBooleanProperty("replicate.packer.typeprefix", true) && + !storageId.contains(typePrefixSeparator)) { String typePrefix = null; - - try - { - //Get object associated with this handle + + try { + // Get object associated with this handle DSpaceObject dso = handleService.resolveToObject(context, objId); - //typePrefix format = 'TYPE@' - if(dso!=null) + // typePrefix format = 'TYPE@' + if (dso != null) { typePrefix = Constants.typeText[dso.getType()] + typePrefixSeparator; + } + } catch (SQLException sqle) { + // do nothing, just ignore -- we'll handle this in a moment } - catch(SQLException sqle) - { - //do nothing, just ignore -- we'll handle this in a moment - } - + // If we were unable to determine a type prefix, then this must mean the object // no longer exists in DSpace! Let's see if we can find it in storage! - if(typePrefix==null) - { - try - { - //Currently we need to try and lookup the object in storage - //Hopefully, there will be an easier way to do this in the future - - //see if this object exists in main storage group + if (typePrefix == null) { + try { + // Currently we need to try and lookup the object in storage + // Hopefully, there will be an easier way to do this in the future + + // see if this object exists in main storage group typePrefix = findTypePrefix(storeGroupName, storageId); - if(typePrefix==null && deleteGroupName!=null) //if not found, check deletion group as well + + // if not found, check deletion group as well + if (typePrefix == null && deleteGroupName != null) { typePrefix = findTypePrefix(deleteGroupName, storageId); + } + } catch (IOException ioE) { + // do nothing, just ignore } - catch(IOException io) - { - //do nothing, just ignore - } - } - - //if we found a typePrefix, prepend it on storageId - if(typePrefix!=null) + } + + // if we found a typePrefix, prepend it on storageId + if (typePrefix != null) { storageId = typePrefix + storageId; + } } - - + // Return final storage ID return storageId; } - + /** * Convert a Storage ID back into a Canonical Identifier * (opposite of 'storageId()' method). * @param storageId the given object's storage ID * @return the objects canonical identifier */ - public String canonicalId(String storageId) - { - //If this 'storageId' includes a TYPE prefix (see 'storageId()' method), + public String canonicalId(String storageId) { + // If this 'storageId' includes a TYPE prefix (see 'storageId()' method), // then remove it, before returning the reformatted ID. - if(storageId.contains(typePrefixSeparator)) - storageId = storageId.substring(storageId.indexOf(typePrefixSeparator)+1); - - //If this 'storageId' includes a file extension suffix, also remove it. - if(storageId.contains(".")) + if (storageId.contains(typePrefixSeparator)) { + storageId = storageId.substring(storageId.indexOf(typePrefixSeparator) + 1); + } + + // If this 'storageId' includes a file extension suffix, also remove it. + if (storageId.contains(".")) { storageId = storageId.substring(0, storageId.indexOf(".")); - - //Finally revert all dashes back to slashes (to create the original canonical ID) + } + + // Finally revert all dashes back to slashes (to create the original canonical ID) return storageId.replaceAll("-", "/"); } @@ -213,53 +200,46 @@ public String canonicalId(String storageId) * @param fileExtension - file extension, if any (may be null) * @return reformatted storage ID for this object (including file extension) */ - public String deletionCatalogId(String objId, String fileExtension) - { + public String deletionCatalogId(String objId, String fileExtension) { // canonical handle notation bedevils file system semantics String storageId = objId.replaceAll("/", "-"); // add appropriate file extension, if needed - if(fileExtension!=null && !storageId.endsWith("." + fileExtension)) + if (fileExtension != null && !storageId.endsWith("." + fileExtension)) { storageId = storageId + "." + fileExtension; + } - if(configurationService.getBooleanProperty("replicate.packer.typeprefix", true) && - !storageId.contains(typePrefixSeparator)) - { - //Prepend the "deletion catalog" type prefix on the name + if (configurationService.getBooleanProperty("replicate.packer.typeprefix", true) && + !storageId.contains(typePrefixSeparator)) { + // Prepend the "deletion catalog" type prefix on the name return deletionCatalogPrefix + typePrefixSeparator + storageId; - } - else - { + } else { // Otherwise, just return the cleaned up ID return storageId; } } - public Odometer getOdometer() throws IOException - { + public Odometer getOdometer() throws IOException { // return a new read-only copy return new Odometer(repDir, true); } // Replica store-backed methods - public File fetchObject(Context context, String group, String objId) throws IOException - { - //String repId = safeId(id) + "." + arFmt; + public File fetchObject(Context context, String group, String objId) throws IOException { + // String repId = safeId(id) + "." + arFmt; File file = stage(context, group, objId); long size = objStore.fetchObject(group, objId, file); - if (size > 0L) - { - synchronized (odoLock) - { + if (size > 0L) { + synchronized (odoLock) { odometer.adjustProperty(DOWNLOADED, size); odometer.save(); } } - + return file.exists() ? file : null; } - + public void transferObject(String group, File file) throws IOException { String psStr = objStore.objectAttribute(group, file.getName(), "sizebytes"); long prevSize = psStr != null ? Long.valueOf(psStr) : 0L; @@ -274,9 +254,9 @@ public void transferObject(String group, File file) throws IOException { } odometer.save(); } - } + } } - + public boolean objectExists(String group, String objId) throws IOException { return objStore.objectExists(group, objId); } @@ -295,18 +275,19 @@ public void removeObject(String group, String objId) throws IOException { } } } - + public boolean moveObject(String srcGroup, String destGroup, String objId) throws IOException { long size = objStore.moveObject(srcGroup, destGroup, objId); - - // NOTE: no need to adjust the odometer. In this case we haven't - // actually uploaded or downloaded any content. - if (size > 0L) + + // NOTE: no need to adjust the odometer. In this case we haven't + // actually uploaded or downloaded any content. + if (size > 0L) { return true; - else + } else { return false; + } } - + /** * This method is only called if we cannot determine an object's type prefix * via DSpace (i.e. the object no longer exists in DSpace). In this case, @@ -317,46 +298,44 @@ public boolean moveObject(String srcGroup, String destGroup, String objId) throw * @param baseId base object id we are looking for (without type prefix) * @return Type prefix if a matching object is located successfully. Null otherwise. */ - private String findTypePrefix(String group, String baseId) throws IOException - { + private String findTypePrefix(String group, String baseId) throws IOException { boolean exists = false; - + // This next part may look a bit like a hack, but it's actually safer than // it seems. Essentially, we are going to try to "guess" what the Type Prefix // may be, and see if we can find an object with that name in our object Store. // The reason this is still "safe" is that the "objId" should be unique with or without - // the Type prefix. Even if it wasn't unique, DSpace HandleManager has checks in place - // to ensure we can never restore an object of a different Type to a Handle that was + // the Type prefix. Even if it wasn't unique, DSpace HandleManager has checks in place + // to ensure we can never restore an object of a different Type to a Handle that was // used previously (e.g. cannot restore an Item with a handle that was previously used by a Collection) - + // NOTE: If DSpace ever provided a way to lookup Object type for an unbound handle, then // we may no longer need to guess which type this object may have been. // ALTERNATIVELY: If DuraCloud & other stores provide a way to search by file properties, we could change // our store plugins to always save the object handle as a property & retrieve files via that property. - //Most objects are Items, so lets see if this object can be found with an Item Type prefix + // Most objects are Items, so lets see if this object can be found with an Item Type prefix String typePrefix = Constants.typeText[Constants.ITEM] + typePrefixSeparator; exists = objStore.objectExists(group, typePrefix + baseId); - if(!exists) - { - //Ok, our second guess will be that this used to be a Collection + if (!exists) { + // Ok, our second guess will be that this used to be a Collection typePrefix = Constants.typeText[Constants.COLLECTION] + typePrefixSeparator; exists = objStore.objectExists(group, typePrefix + baseId); } - if(!exists) - { - //Final guess: maybe this used to be a Community? + if (!exists) { + // Final guess: maybe this used to be a Community? typePrefix = Constants.typeText[Constants.COMMUNITY] + typePrefixSeparator; exists = objStore.objectExists(group, typePrefix + baseId); - } - - // That's it. We're done guessing. If we still couldn't find this object, + } + + // That's it. We're done guessing. If we still couldn't find this object, // it obviously doesn't exist in our object Store. - if(exists) + if (exists) { return typePrefix; - else + } else { return null; + } } } diff --git a/src/main/java/org/dspace/ctask/replicate/TransmitAIP.java b/src/main/java/org/dspace/ctask/replicate/TransmitAIP.java index eddc8ff4..4ace89d8 100644 --- a/src/main/java/org/dspace/ctask/replicate/TransmitAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/TransmitAIP.java @@ -30,7 +30,7 @@ *

* This task is "suspendable" when invoked from the UI. If a single AIP fails * to be generated and transmitted to storage, we should inform the user ASAP. - * We wouldn't want them to assume everything was transferred successfully, + * We wouldn't want them to assume everything was transferred successfully, * if there were actually underlying errors. *

* Note that this task has a companion task called TransmitSingleAIP which @@ -40,9 +40,8 @@ * @see PackerFactory * @see TransmitSingleAIP */ -@Suspendable(invoked=Curator.Invoked.INTERACTIVE) -public class TransmitAIP extends AbstractCurationTask -{ +@Suspendable(invoked = Curator.Invoked.INTERACTIVE) +public class TransmitAIP extends AbstractCurationTask { // Group where all AIPs will be stored private String storeGroupName; @@ -52,7 +51,6 @@ public void init(Curator curator, String taskId) throws IOException { storeGroupName = configurationService.getProperty("replicate.group.aip.name"); } - /** * Perform 'Transmit AIP' task *

@@ -62,22 +60,19 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); - - try - { + + try { Context context = Curator.curationContext(); Packer packer = PackerFactory.instance(context, dso); File archive = packer.pack(repMan.stage(context, storeGroupName, dso.getHandle())); - String msg = "Created AIP: '" + archive.getName() + + String msg = "Created AIP: '" + archive.getName() + "' size: " + archive.length(); repMan.transferObject(storeGroupName, archive); setResult(msg); return Curator.CURATE_SUCCESS; - } - catch (AuthorizeException | SQLException e) { + } catch (AuthorizeException | SQLException e) { throw new IOException(e); } } diff --git a/src/main/java/org/dspace/ctask/replicate/TransmitSingleAIP.java b/src/main/java/org/dspace/ctask/replicate/TransmitSingleAIP.java index 9849f187..8938583a 100644 --- a/src/main/java/org/dspace/ctask/replicate/TransmitSingleAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/TransmitSingleAIP.java @@ -18,7 +18,7 @@ * inhibits container iteration (distribution to members) when invoked upon * a container object. *

- * This task is primarily for usage via the ReplicateConsumer, as it needs to + * This task is primarily for usage via the ReplicateConsumer, as it needs to * interact with a single object at a time. *

* The type of AIP produced is based on the 'packer.pkgtype' setting diff --git a/src/main/java/org/dspace/ctask/replicate/VerifyAIP.java b/src/main/java/org/dspace/ctask/replicate/VerifyAIP.java index 71799314..84d25cf5 100644 --- a/src/main/java/org/dspace/ctask/replicate/VerifyAIP.java +++ b/src/main/java/org/dspace/ctask/replicate/VerifyAIP.java @@ -30,16 +30,15 @@ * @author richardrodgers * @see TransmitAIP */ -@Suspendable(invoked=Curator.Invoked.INTERACTIVE) -public class VerifyAIP extends AbstractCurationTask -{ +@Suspendable(invoked = Curator.Invoked.INTERACTIVE) +public class VerifyAIP extends AbstractCurationTask { private String archFmt; // Group where all AIPs are stored private String storeGroupName; @Override - public void init(Curator curator, String taskId) throws IOException{ + public void init(Curator curator, String taskId) throws IOException { super.init(curator, taskId); archFmt = configurationService.getProperty("replicate.packer.archfmt"); storeGroupName = configurationService.getProperty("replicate.group.aip.name"); @@ -54,17 +53,14 @@ public void init(Curator curator, String taskId) throws IOException{ * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { - if(dso!=null) { + public int perform(DSpaceObject dso) throws IOException { + if (dso != null) { try { return perform(Curator.curationContext(), dso.getHandle()); } catch (SQLException e) { throw new IOException(e); } - } - else - { + } else { String result = "DSpace Object not found!"; report(result); setResult(result); @@ -82,12 +78,12 @@ public int perform(DSpaceObject dso) throws IOException * @throws IOException if I/O error */ @Override - public int perform(Context ctx, String id) throws IOException - { + public int perform(Context ctx, String id) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); String objId = repMan.storageId(ctx, id, archFmt); boolean found = repMan.objectExists(storeGroupName, objId); + String result = "AIP for object: " + id + " found: " + found; report(result); setResult(result); diff --git a/src/main/java/org/dspace/ctask/replicate/checkm/CompareWithManifest.java b/src/main/java/org/dspace/ctask/replicate/checkm/CompareWithManifest.java index 041366e6..871b2d1d 100644 --- a/src/main/java/org/dspace/ctask/replicate/checkm/CompareWithManifest.java +++ b/src/main/java/org/dspace/ctask/replicate/checkm/CompareWithManifest.java @@ -37,10 +37,9 @@ * @see TransmitManifest */ @Distributive -public class CompareWithManifest extends AbstractCurationTask -{ +public class CompareWithManifest extends AbstractCurationTask { private String result = null; - + // Group where all Manifests will be stored private String manifestGroupName; @@ -57,31 +56,27 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); - - try - { + + try { Context context = Curator.curationContext(); String filename = repMan.storageId(context, dso.getHandle(), TransmitManifest.MANIFEST_EXTENSION); int status = checkManifest(repMan, filename, context); - //report the final result + // report the final result report(result); setResult(result); return status; - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE); } } - + /** * This method recursively checks Manifests. *

- * In a sense, all this is checking is that Bitstreams (files) have not changed within + * In a sense, all this is checking is that Bitstreams (files) have not changed within * the current DSpace object. So, if the current object is a Site, Community or Collection, * its manifest is not validated (as those manifests just point at other sub-manifests). Rather, * this method recursively loads manifests until it locates all Item-level manifests. Then it @@ -94,73 +89,58 @@ public int perform(DSpaceObject dso) throws IOException * @throws SQLException if database error * @return integer which represents Curator return status */ - private int checkManifest(ReplicaManager repMan, String filename, Context context) throws IOException, SQLException - { + private int checkManifest(ReplicaManager repMan, String filename, Context context) + throws IOException, SQLException { File manFile = repMan.fetchObject(context, manifestGroupName, filename); - if (manFile != null) - { + if (manFile != null) { Item item = null; Map bsMap = new HashMap<>(); BufferedReader reader = new BufferedReader(new FileReader(manFile)); String line = null; - while ((line = reader.readLine()) != null) - { - if (! line.startsWith("#")) // skip comments - { + while ((line = reader.readLine()) != null) { + if (! line.startsWith("#")) { // skip comments String entry = line.substring(0, line.indexOf("|")); // if there's a dash in the first entry, then it just // refers to a sub manifest - if (entry.indexOf("-") > 0) - { + if (entry.indexOf("-") > 0) { // it's another manifest - fetch & check it item = null; bsMap.clear(); int status = checkManifest(repMan, entry, context); - - //if manifest failed check, return immediately (otherwise we'll continue processing) - if(status == Curator.CURATE_FAIL) + + // if manifest failed check, return immediately (otherwise we'll continue processing) + if (status == Curator.CURATE_FAIL) { return status; - } - else - { + } + } else { // first entry is a bitstream reference. So, check it int cut = entry.lastIndexOf("/"); - if (item == null) - { + if (item == null) { // look up object first & map bitstreams by seqID String handle = entry.substring(0, cut); DSpaceObject dso = handleService.resolveToObject(context, handle); - if (dso != null && dso instanceof Item) - { + if (dso != null && dso instanceof Item) { item = (Item)dso; - for (Bundle bundle : item.getBundles()) - { - for (Bitstream bs : bundle.getBitstreams()) - { + for (Bundle bundle : item.getBundles()) { + for (Bitstream bs : bundle.getBitstreams()) { bsMap.put(Integer.toString(bs.getSequenceID()), bs); } } - } - else - { + } else { result = "No item found for manifest entry: " + handle; return Curator.CURATE_FAIL; } } String seqId = entry.substring(cut + 1); Bitstream bs = bsMap.get(seqId); - if (bs != null) - { + if (bs != null) { String[] parts = line.split("\\|"); // compare checksums - if (! bs.getChecksum().equals(parts[2])) - { + if (! bs.getChecksum().equals(parts[2])) { result = "Bitstream: " + seqId + " differs from manifest: " + entry; return Curator.CURATE_FAIL; } - } - else - { + } else { result = "No bitstream: " + seqId + " found for manifest entry: " + entry; return Curator.CURATE_FAIL; } @@ -168,15 +148,13 @@ private int checkManifest(ReplicaManager repMan, String filename, Context contex } } reader.close(); - - //finished checking this entire manifest -- it was successful! + + // finished checking this entire manifest -- it was successful! result = "Manifest and repository content agree"; return Curator.CURATE_SUCCESS; - } - else - { + } else { result = "No manifest file found: " + filename; - return Curator.CURATE_FAIL; + return Curator.CURATE_FAIL; } } } diff --git a/src/main/java/org/dspace/ctask/replicate/checkm/FetchManifest.java b/src/main/java/org/dspace/ctask/replicate/checkm/FetchManifest.java index a026dd16..b32fa688 100644 --- a/src/main/java/org/dspace/ctask/replicate/checkm/FetchManifest.java +++ b/src/main/java/org/dspace/ctask/replicate/checkm/FetchManifest.java @@ -29,8 +29,7 @@ * @see TransmitManifest */ -public class FetchManifest extends AbstractCurationTask -{ +public class FetchManifest extends AbstractCurationTask { private String archFmt; // Group where all Manifests are stored @@ -42,7 +41,7 @@ public void init(Curator curator, String taskId) throws IOException { archFmt = configurationService.getProperty("replicate.packer.archfmt"); manifestGroupName = configurationService.getProperty("replicate.group.manifest.name"); } - + /** * Perform 'Fetch Manifest' task * @param dso DSpace Object to perform on @@ -50,8 +49,7 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { try { Context context = Curator.curationContext(); ReplicaManager repMan = ReplicaManager.instance(); diff --git a/src/main/java/org/dspace/ctask/replicate/checkm/RemoveManifest.java b/src/main/java/org/dspace/ctask/replicate/checkm/RemoveManifest.java index 6296d01b..30f9c539 100644 --- a/src/main/java/org/dspace/ctask/replicate/checkm/RemoveManifest.java +++ b/src/main/java/org/dspace/ctask/replicate/checkm/RemoveManifest.java @@ -31,7 +31,7 @@ /** * RemoveManifest task will remove the manifest of requested objects from the - * replica store. If the manifest is multi-level, all the manifests of its + * replica store. If the manifest is multi-level, all the manifests of its * children (members) will also be removed. *

* Manifests conform to the CDL Checkm v0.7 manifest format spec. @@ -54,7 +54,7 @@ public void init(Curator curator, String taskId) throws IOException { super.init(curator, taskId); manifestGroupName = configurationService.getProperty("replicate.group.manifest.name"); } - + /** * Removes replicas of passed object from the replica store. * If a container, removes all the member replicas, in addition @@ -66,8 +66,7 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); try { Context context = Curator.curationContext(); @@ -84,7 +83,7 @@ public int perform(DSpaceObject dso) throws IOException * If object has any associated child objects, their existing manifests * are also removed from the Replica ObjectStore. *

- * NOTE: this method does NOT remove the DSpace Object itself (nor any + * NOTE: this method does NOT remove the DSpace Object itself (nor any * children) from the DSpace repository. It only removes the associated * manifests from the Replica ObjectStore. * @@ -94,8 +93,7 @@ public int perform(DSpaceObject dso) throws IOException * @throws IOException if I/O error * @throws SQLException if database error */ - private void remove(Context context, ReplicaManager repMan, DSpaceObject dso) throws IOException, SQLException - { + private void remove(Context context, ReplicaManager repMan, DSpaceObject dso) throws IOException, SQLException { String objId = repMan.storageId(context, dso.getHandle(), TransmitManifest.MANIFEST_EXTENSION); repMan.removeObject(manifestGroupName, objId); report("Removing manifest for: " + objId); @@ -139,8 +137,7 @@ private void remove(Context context, ReplicaManager repMan, DSpaceObject dso) th * @throws IOException if I/O error */ @Override - public int perform(Context ctx, String id) throws IOException - { + public int perform(Context ctx, String id) throws IOException { DSpaceObject dso = dereference(ctx, id); if (dso != null) { return perform(dso); @@ -150,13 +147,13 @@ public int perform(Context ctx, String id) throws IOException setResult("Manifest for '" + id + "' has been removed"); return Curator.CURATE_SUCCESS; } - + /** * Removes a DSpace Object's Manifest from the Replica ObjectStore. * If object has any associated child objects, their existing manifests * are also removed from the Replica ObjectStore. *

- * NOTE: this method does NOT remove the DSpace Object itself (nor any + * NOTE: this method does NOT remove the DSpace Object itself (nor any * children) from the DSpace repository. It only removes the associated * manifests from the Replica ObjectStore. * @@ -165,8 +162,7 @@ public int perform(Context ctx, String id) throws IOException * @param id the DSpace Object's identifier * @throws IOException if I/O error */ - private void deleteManifest(Context context, ReplicaManager repMan, String id) throws IOException - { + private void deleteManifest(Context context, ReplicaManager repMan, String id) throws IOException { File manFile = repMan.fetchObject(context, manifestGroupName, id); if (manFile != null) { BufferedReader reader = new BufferedReader(new FileReader(manFile)); diff --git a/src/main/java/org/dspace/ctask/replicate/checkm/TransmitManifest.java b/src/main/java/org/dspace/ctask/replicate/checkm/TransmitManifest.java index 3c06df24..dd2cc712 100644 --- a/src/main/java/org/dspace/ctask/replicate/checkm/TransmitManifest.java +++ b/src/main/java/org/dspace/ctask/replicate/checkm/TransmitManifest.java @@ -51,17 +51,17 @@ @Distributive public class TransmitManifest extends AbstractCurationTask { - //Version of CDL Checkm spec that this manifest conforms to + // Version of CDL Checkm spec that this manifest conforms to private static final String CKM_VSN = "0.7"; - - //Format extension for manifest files + + // Format extension for manifest files protected static final String MANIFEST_EXTENSION = "txt"; private String template = null; - + // Group where all Manifests will be stored private String manifestGroupName; - + private static Logger log = LogManager.getLogger(); private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); @@ -73,7 +73,7 @@ public void init(Curator curator, String taskId) throws IOException { template = configurationService.getProperty("replicate.checkm.template"); manifestGroupName = configurationService.getProperty("replicate.group.manifest.name"); } - + /** * Perform 'Transmit Manifest' task *

@@ -83,45 +83,34 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { ReplicaManager repMan = ReplicaManager.instance(); - try - { + try { Context context = Curator.curationContext(); File manFile = null; int type = dso.getType(); - if (Constants.ITEM == type) - { + if (Constants.ITEM == type) { manFile = itemManifest(context, repMan, (Item)dso); - } - else if (Constants.COLLECTION == type) - { + } else if (Constants.COLLECTION == type) { // create manifests for each item - link in collection manifest manFile = collectionManifest(context, repMan, (Collection)dso); - } - else if (Constants.COMMUNITY == type) - { + } else if (Constants.COMMUNITY == type) { // create manifests for Community on down manFile = communityManifest(context, repMan, (Community)dso); - } - else if (Constants.SITE == type) - { + } else if (Constants.SITE == type) { // create manifests for all objects in DSpace manFile = siteManifest(context, repMan, (Site)dso); } - + repMan.transferObject(manifestGroupName, manFile); - } - catch (SQLException sqlE) - { + } catch (SQLException sqlE) { throw new IOException(sqlE); } setResult("Created manifest for: " + dso.getHandle()); return Curator.CURATE_SUCCESS; } - - + + /** * Generate a manifest for the DSpace Site. Also * generate & transfer to replica ObjectStore the manifests for all @@ -134,40 +123,39 @@ else if (Constants.SITE == type) * @throws IOException if I/O error * @throws SQLException if database error */ - private File siteManifest(Context context, ReplicaManager repMan, Site site) throws IOException, SQLException - { - //Manifests stored as text files + private File siteManifest(Context context, ReplicaManager repMan, Site site) throws IOException, SQLException { + // Manifests stored as text files String filename = repMan.storageId(context, site.getHandle(), MANIFEST_EXTENSION); - + log.debug("Creating manifest for: " + site.getHandle()); - + //Create site manifest File manFile = repMan.stage(context, manifestGroupName, filename); Writer writer = manifestWriter(manFile); int count = 0; - + List topCommunities = communityService.findAllTop(context); - //Create top-level community manifests & transfer each - for (Community comm : topCommunities) - { + // Create top-level community manifests & transfer each + for (Community comm : topCommunities) { File scFile = communityManifest(context, repMan, comm); writer.write(tokenized(scFile) + "\n"); count++; repMan.transferObject(manifestGroupName, scFile); } - if (count == 0) - { + + if (count == 0) { // write EOF marker to prevent confusion if container empty writer.write("#%eof" + "\n"); } + writer.close(); report("Created manifest for: " + site.getHandle()); return manFile; } - + /** * Generate a manifest for the specified DSpace Community. Also - * generate & transfer to replica ObjectStore the manifests for any child + * generate & transfer to replica ObjectStore the manifests for any child * objects (sub-communities, collections). * * @param context the context to use @@ -178,38 +166,37 @@ private File siteManifest(Context context, ReplicaManager repMan, Site site) thr * @throws SQLException if database error */ private File communityManifest(Context context, ReplicaManager repMan, Community comm) throws IOException, - SQLException - { - //Manifests stored as text files + SQLException { + // Manifests stored as text files String filename = repMan.storageId(context, comm.getHandle(), MANIFEST_EXTENSION); - + log.debug("Creating manifest for: " + comm.getHandle()); - - //Create community manifest + + // Create community manifest File manFile = repMan.stage(context, manifestGroupName, filename); Writer writer = manifestWriter(manFile); int count = 0; - //Create sub-community manifests & transfer each - for (Community subComm : comm.getSubcommunities()) - { + // Create sub-community manifests & transfer each + for (Community subComm : comm.getSubcommunities()) { File scFile = communityManifest(context, repMan, subComm); writer.write(tokenized(scFile) + "\n"); count++; - repMan.transferObject(manifestGroupName, scFile); + repMan.transferObject(manifestGroupName, scFile); } - //Create collection manifests & transfer each - for (Collection coll: comm.getCollections()) - { + + // Create collection manifests & transfer each + for (Collection coll: comm.getCollections()) { File colFile = collectionManifest(context, repMan, coll); writer.write(tokenized(colFile) + "\n"); count++; repMan.transferObject(manifestGroupName, colFile); } - if (count == 0) - { + + if (count == 0) { // write EOF marker to prevent confusion if container empty writer.write("#%eof" + "\n"); } + writer.close(); report("Created manifest for: " + comm.getHandle()); return manFile; @@ -217,7 +204,7 @@ private File communityManifest(Context context, ReplicaManager repMan, Community /** * Generate a manifest for the specified DSpace Collection. Also - * generate & transfer to replica ObjectStore the manifests for any child + * generate & transfer to replica ObjectStore the manifests for any child * objects (items). * * @param context the context to use @@ -228,32 +215,31 @@ private File communityManifest(Context context, ReplicaManager repMan, Community * @throws SQLException if database error */ private File collectionManifest(Context context, ReplicaManager repMan, Collection coll) throws IOException, - SQLException - { - //Manifests stored as text files + SQLException { + // Manifests stored as text files String filename = repMan.storageId(context, coll.getHandle(), MANIFEST_EXTENSION); - + log.debug("Creating manifest for: " + coll.getHandle()); - + //Create Collection manifest File manFile = repMan.stage(context, manifestGroupName, filename); Writer writer = manifestWriter(manFile); int count = 0; - - //Create all Item manifests & transfer each + + // Create all Item manifests & transfer each Iterator ii = itemService.findByCollection(context, coll); - while (ii.hasNext()) - { + while (ii.hasNext()) { File itemMan = itemManifest(context, repMan, ii.next()); count++; writer.write(tokenized(itemMan) + "\n"); repMan.transferObject(manifestGroupName, itemMan); } - if (count == 0) - { + + if (count == 0) { // write EOF marker to prevent confusion if container empty writer.write("#%eof" + "\n"); } + writer.close(); report("Created manifest for: " + coll.getHandle()); return manFile; @@ -269,35 +255,29 @@ private File collectionManifest(Context context, ReplicaManager repMan, Collecti * @throws IOException if I/O error * @throws SQLException if database error */ - private File itemManifest(Context context, ReplicaManager repMan, Item item) throws IOException, SQLException - { + private File itemManifest(Context context, ReplicaManager repMan, Item item) throws IOException, SQLException { String filename = repMan.storageId(context, item.getHandle(), MANIFEST_EXTENSION); - + log.debug("Creating manifest for: " + item.getHandle()); - + //Create Item manifest File manFile = repMan.stage(context, manifestGroupName, filename); Writer writer = manifestWriter(manFile); - + // look through all ORIGINAL bitstreams, and add // information about each (e.g. checksum) to manifest int count = 0; List bundles = itemService.getBundles(item, "ORIGINAL"); - if(bundles!=null && bundles.size()>0) - { - //there should be only one ORIGINAL bundle + if (bundles != null && !bundles.isEmpty()) { + // there should be only one ORIGINAL bundle Bundle bundle = bundles.get(0); - for (Bitstream bs : bundle.getBitstreams()) - { + for (Bitstream bs : bundle.getBitstreams()) { int i = 0; StringBuilder sb = new StringBuilder(); - for (String token : Arrays.asList(template.split("\\|"))) - { - if (! token.startsWith("x")) - { + for (String token : Arrays.asList(template.split("\\|"))) { + if (!token.startsWith("x")) { // tokens are positionally defined - switch (i) - { + switch (i) { case 0: // what URL/name format? sb.append(item.getHandle()).append("/").append(bs.getSequenceID()); @@ -329,16 +309,15 @@ private File itemManifest(Context context, ReplicaManager repMan, Item item) thr } count++; writer.write(sb.substring(0, sb.length() - 1) + "\n"); - } //end for each bitstream - }//end if ORIGINAL bundle - - //If no bitstreams found, then this is an empty manifest - if (count == 0) - { + } // end for each bitstream + } // end if ORIGINAL bundle + + // If no bitstreams found, then this is an empty manifest + if (count == 0) { // write EOF marker to prevent confusion if container empty writer.write("#%eof" + "\n"); } - + writer.close(); report("Created manifest for: " + item.getHandle()); return manFile; @@ -350,8 +329,7 @@ private File itemManifest(Context context, ReplicaManager repMan, Item item) thr * @return reference to Writer * @throws IOException if I/O error */ - private Writer manifestWriter(File file) throws IOException - { + private Writer manifestWriter(File file) throws IOException { FileWriter writer = new FileWriter(file); writer.write("#%checkm_" + CKM_VSN + "\n"); // write out template as explanatory metadata @@ -359,14 +337,11 @@ private Writer manifestWriter(File file) throws IOException return writer; } - private String tokenized(File file) throws IOException - { + private String tokenized(File file) throws IOException { int i = 0; StringBuilder sb = new StringBuilder(); - for (String token : Arrays.asList(template.split("\\|"))) - { - if (! token.startsWith("x")) - { + for (String token : Arrays.asList(template.split("\\|"))) { + if (!token.startsWith("x")) { // tokens are positionally defined switch (i) { case 0: @@ -390,9 +365,9 @@ private String tokenized(File file) throws IOException sb.append(file.lastModified()); break; case 5: - // target name - skip for now + // target name - skip for now default: - break; + break; } } sb.append("|"); diff --git a/src/main/java/org/dspace/ctask/replicate/checkm/VerifyManifest.java b/src/main/java/org/dspace/ctask/replicate/checkm/VerifyManifest.java index 78ba505b..877163f1 100644 --- a/src/main/java/org/dspace/ctask/replicate/checkm/VerifyManifest.java +++ b/src/main/java/org/dspace/ctask/replicate/checkm/VerifyManifest.java @@ -34,7 +34,7 @@ * @author richardrodgers * @see TransmitManifest */ -@Suspendable(invoked=Curator.Invoked.INTERACTIVE) +@Suspendable(invoked = Curator.Invoked.INTERACTIVE) public class VerifyManifest extends AbstractCurationTask { // Group where all Manifests are stored @@ -53,14 +53,14 @@ public void init(Curator curator, String taskId) throws IOException { * @throws IOException if I/O error */ @Override - public int perform(DSpaceObject dso) throws IOException - { + public int perform(DSpaceObject dso) throws IOException { Context context; try { context = Curator.curationContext(); } catch (SQLException e) { throw new IOException(e); } + ReplicaManager repMan = ReplicaManager.instance(); String objId = repMan.storageId(context, dso.getHandle(), TransmitManifest.MANIFEST_EXTENSION); boolean found = repMan.objectExists(manifestGroupName, objId); diff --git a/src/main/java/org/dspace/ctask/replicate/store/DuraCloudObjectStore.java b/src/main/java/org/dspace/ctask/replicate/store/DuraCloudObjectStore.java index 50c5df66..3d0318af 100644 --- a/src/main/java/org/dspace/ctask/replicate/store/DuraCloudObjectStore.java +++ b/src/main/java/org/dspace/ctask/replicate/store/DuraCloudObjectStore.java @@ -76,12 +76,14 @@ public void init() throws IOException { defaultWait = configurationService.getIntProperty("duracloud.retry.wait", DEFAULT_WAIT_BETWEEN_RETRIES); waitMultiplier = configurationService.getIntProperty("duracloud.retry.multiplier", DEFAULT_WAIT_MULTIPLIER); + // Attempt to get Content Store from a parameter in the configuration + String storeId = configurationService.getProperty("duracloud.store-id", "0"); try { - //Get the primary content store (e.g. Amazon) - dcStore = storeManager.getPrimaryContentStore(); + dcStore = storeManager.getContentStore(storeId); } catch (ContentStoreException csE) { - throw new IOException("Unable to connect to the DuraCloud Primary Content Store. Please check the " + - "DuraCloud connection/authentication settings in your 'duracloud.cfg' file.", csE); + throw new IOException("Unable to connect to the DuraCloud Content Store. " + + "Please check the DuraCloud connection/authentication settings " + + "and the store-id setting in your 'duracloud.cfg' file.", csE); } } @@ -95,7 +97,7 @@ public long fetchObject(final String group, final String id, final File file) th String contentSizeHeader = content.getProperties().get(ContentStore.CONTENT_SIZE); try { size = Long.parseLong(contentSizeHeader); - } catch(NumberFormatException nfe) { + } catch (NumberFormatException nfe) { // ignore - header was missing or not a valid Long. We will determine size below } @@ -148,6 +150,7 @@ public long removeObject(String group, String id) throws IOException { public long transferObject(String group, File file) throws IOException { long size = 0L; String chkSum = Utils.checksum(file, "MD5"); + // make sure this is a different file from what replica store has // to avoid network I/O tax try { @@ -162,6 +165,7 @@ public long transferObject(String group, File file) throws IOException { } catch (ContentStoreException csE) { throw new IOException(csE); } + // delete staging file file.delete(); return size; @@ -249,11 +253,12 @@ public String objectAttribute(String group, String id, String attrName) throws I * @return DuraCloud Space ID */ private String getSpaceID(String group) { - //If group contains a forward or backslash, then the - //Space ID is whatever is before that slash - if (group!=null && group.contains("/")) { + // If group contains a forward or backslash, then the + // Space ID is whatever is before that slash + if (group != null && group.contains("/")) { return group.substring(0, group.indexOf("/")); - } else { // otherwise, the passed in group is the Space ID + } else { + // otherwise, the passed in group is the Space ID return group; } } @@ -269,11 +274,12 @@ private String getSpaceID(String group) { * @return content prefix (ending with a forward slash) */ private String getContentPrefix(String group) { - //If group contains a forward or backslash, then the + // If group contains a forward or backslash, then the // content prefix is whatever is after that slash - if (group!=null && group.contains("/")) { + if (group != null && group.contains("/")) { return group.substring(group.indexOf("/") + 1) + "/"; - } else { // otherwise, no content prefix is specified + } else { + // otherwise, no content prefix is specified return ""; } } diff --git a/src/main/java/org/dspace/ctask/replicate/store/LocalObjectStore.java b/src/main/java/org/dspace/ctask/replicate/store/LocalObjectStore.java index e06f02d0..474633cd 100644 --- a/src/main/java/org/dspace/ctask/replicate/store/LocalObjectStore.java +++ b/src/main/java/org/dspace/ctask/replicate/store/LocalObjectStore.java @@ -34,30 +34,28 @@ public class LocalObjectStore implements ObjectStore { // where replicas are kept protected String storeDir = null; - + // need no-arg constructor for PluginManager public LocalObjectStore() { } @Override - public void init() throws IOException - { + public void init() throws IOException { storeDir = configurationService.getProperty("replicate.store.dir"); + File storeFile = new File(storeDir); - if (! storeFile.exists()) - { + if (! storeFile.exists()) { storeFile.mkdirs(); } } @Override - public long fetchObject(String group, String id, File file) throws IOException - { + public long fetchObject(String group, String id, File file) throws IOException { // locate archive and copy to file long size = 0L; + File archFile = new File(storeDir + File.separator + group, id); - if (archFile.exists()) - { + if (archFile.exists()) { size = archFile.length(); Utils.copy(archFile, file); } @@ -65,20 +63,18 @@ public long fetchObject(String group, String id, File file) throws IOException } @Override - public boolean objectExists(String group, String id) - { + public boolean objectExists(String group, String id) { // do we have a copy in our managed area? return new File(storeDir + File.separator + group, id).exists(); } @Override - public long removeObject(String group, String id) - { + public long removeObject(String group, String id) { // remove file if present long size = 0L; + File remFile = new File(storeDir + File.separator + group, id); - if (remFile.exists()) - { + if (remFile.exists()) { size = remFile.length(); remFile.delete(); } @@ -86,61 +82,54 @@ public long removeObject(String group, String id) } @Override - public long transferObject(String group, File file) throws IOException - { + public long transferObject(String group, File file) throws IOException { // local transfer is a simple matter of renaming the file, // we don't bother checking if replica is really new, since // local deletes/copies are cheap + File archDir = new File(storeDir, group); - if (! archDir.isDirectory()) - { + if (!archDir.isDirectory()) { archDir.mkdirs(); } + File archFile = new File(archDir, file.getName()); - if (archFile.exists()) - { + if (archFile.exists()) { archFile.delete(); } - if (! file.renameTo(archFile)) - { - throw new UnsupportedOperationException("Store does not support rename"); + + if (!file.renameTo(archFile)) { + throw new UnsupportedOperationException("Store does not support rename."); } + return archFile.length(); } @Override - public String objectAttribute(String group, String id, String attrName) throws IOException - { + public String objectAttribute(String group, String id, String attrName) throws IOException { File archFile = new File(storeDir + File.separator + group, id); - if ("checksum".equals(attrName)) - { + if ("checksum".equals(attrName)) { return Utils.checksum(archFile, "MD5"); - } - else if ("sizebytes".equals(attrName)) - { + } else if ("sizebytes".equals(attrName)) { return String.valueOf(archFile.length()); - } - else if ("modified".equals(attrName)) - { + } else if ("modified".equals(attrName)) { return String.valueOf(archFile.lastModified()); } + return null; } - + @Override - public long moveObject(String srcGroup, String destGroup, String id) throws IOException - { + public long moveObject(String srcGroup, String destGroup, String id) throws IOException { long size = 0L; - - //Find the file + + // Find the file File file = new File(storeDir + File.separator + srcGroup, id); - if (file.exists()) - { - //If file is found, just transfer it to destination, + if (file.exists()) { + // If file is found, just transfer it to destination, // as transferObject() just does a file rename size = transferObject(destGroup, file); } - + return size; } } diff --git a/src/main/java/org/dspace/ctask/replicate/store/MountableObjectStore.java b/src/main/java/org/dspace/ctask/replicate/store/MountableObjectStore.java index 8b81b3e1..8bfe85f1 100644 --- a/src/main/java/org/dspace/ctask/replicate/store/MountableObjectStore.java +++ b/src/main/java/org/dspace/ctask/replicate/store/MountableObjectStore.java @@ -26,24 +26,22 @@ * * @author richardrodgers */ -public class MountableObjectStore extends LocalObjectStore -{ +public class MountableObjectStore extends LocalObjectStore { // need a no-arg constructor for PluginManager - public MountableObjectStore() - { + public MountableObjectStore() { } @Override - public long transferObject(String group, File file) throws IOException - { + public long transferObject(String group, File file) throws IOException { // local transfer is a simple matter of copying the file, // we don't bother checking if replica is really new, since // local deletes/copies are cheap + File archFile = new File(storeDir + File.separator + group, file.getName()); - if (archFile.exists()) - { + if (archFile.exists()) { archFile.delete(); } + Utils.copy(file, archFile); return file.length(); } diff --git a/src/main/java/org/dspace/pack/Packer.java b/src/main/java/org/dspace/pack/Packer.java index 082ba52c..05d1ebee 100644 --- a/src/main/java/org/dspace/pack/Packer.java +++ b/src/main/java/org/dspace/pack/Packer.java @@ -18,8 +18,7 @@ * * @author richardrodgers */ -public interface Packer -{ +public interface Packer { /** * Packs (maps) the contents of this object into an archive file. * diff --git a/src/main/java/org/dspace/pack/PackerFactory.java b/src/main/java/org/dspace/pack/PackerFactory.java index fa965e6d..6a32957a 100644 --- a/src/main/java/org/dspace/pack/PackerFactory.java +++ b/src/main/java/org/dspace/pack/PackerFactory.java @@ -29,9 +29,7 @@ * * @author richardrodgers */ -public class PackerFactory -{ - +public class PackerFactory { // basic bag property names - some optional public static final String OBJFILE = "object.properties"; public static final String BAG_TYPE = "bagType"; @@ -56,14 +54,18 @@ public class PackerFactory // cached instance of METSPacker - because a little expensive to create private static METSPacker metsPacker = null; + /** + * Private constructor for this utility class + */ + private PackerFactory() {} + public static Packer instance(Context context, DSpaceObject dso) { Packer packer = null; int type = dso.getType(); if ("mets".equals(packType)) { if (metsPacker == null) { metsPacker = new METSPacker(context, dso, archFmt); - } - else { + } else { metsPacker.setContext(context); metsPacker.setDSO(dso); } @@ -83,7 +85,7 @@ public static Packer instance(Context context, DSpaceObject dso) { } else if (Constants.SITE == type) { packer = new SitePacker(context, (Site)dso, archFmt); } else { - throw new RuntimeException("No packer for object type"); + throw new RuntimeException("No packer for object type."); } return packer; } diff --git a/src/main/java/org/dspace/pack/bagit/BagInfoHelper.java b/src/main/java/org/dspace/pack/bagit/BagInfoHelper.java index 96f66412..0f7eaf0a 100644 --- a/src/main/java/org/dspace/pack/bagit/BagInfoHelper.java +++ b/src/main/java/org/dspace/pack/bagit/BagInfoHelper.java @@ -23,6 +23,11 @@ */ public class BagInfoHelper { + /** + * Private constructor for this utility class + */ + private BagInfoHelper() {} + /** * Loads the bag-info.txt and any other fields for tag files found under 'replicate.bag.tag' * @@ -36,7 +41,7 @@ public static Map> getTagFiles() { final List keys = configurationService.getPropertyKeys(TAG_KEY); - // precomplie patterns for when we split strings + // precompile patterns for when we split strings final Pattern dotSplit = Pattern.compile("\\."); final Pattern hyphenSplit = Pattern.compile("-"); @@ -76,5 +81,4 @@ public static Map> getTagFiles() { return tagFiles; } - } diff --git a/src/main/java/org/dspace/pack/bagit/BagItAipReader.java b/src/main/java/org/dspace/pack/bagit/BagItAipReader.java index ef6f12e5..3824e75f 100644 --- a/src/main/java/org/dspace/pack/bagit/BagItAipReader.java +++ b/src/main/java/org/dspace/pack/bagit/BagItAipReader.java @@ -27,9 +27,6 @@ import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Unmarshaller; import com.google.common.base.Optional; import gov.loc.repository.bagit.domain.Bag; @@ -39,6 +36,9 @@ import gov.loc.repository.bagit.exceptions.UnsupportedAlgorithmException; import gov.loc.repository.bagit.reader.BagReader; import gov.loc.repository.bagit.verify.BagVerifier; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Unmarshaller; import org.apache.commons.io.FileUtils; import org.dspace.pack.bagit.xml.metadata.Metadata; import org.dspace.pack.bagit.xml.policy.Policies; @@ -183,7 +183,7 @@ public boolean accept(Path path) { }; Optional logo = Optional.absent(); - try(DirectoryStream bitstreams = Files.newDirectoryStream(bag.resolve(dataDirectory), bitstreamFilter)) { + try (DirectoryStream bitstreams = Files.newDirectoryStream(bag.resolve(dataDirectory), bitstreamFilter)) { final Iterator iterator = bitstreams.iterator(); if (iterator.hasNext()) { logo = Optional.of(iterator.next()); @@ -293,7 +293,7 @@ public boolean accept(Path path) { final String bundleName = bundle.getFileName().toString(); // iterate all bitstreams - try(DirectoryStream bitstreams = Files.newDirectoryStream(bundle, bitstreamFilter)) { + try (DirectoryStream bitstreams = Files.newDirectoryStream(bundle, bitstreamFilter)) { for (Path bitstream : bitstreams) { final String bitstreamName = bitstream.getFileName().toString(); diff --git a/src/main/java/org/dspace/pack/bagit/BagItAipWriter.java b/src/main/java/org/dspace/pack/bagit/BagItAipWriter.java index ef9e43c2..50393344 100644 --- a/src/main/java/org/dspace/pack/bagit/BagItAipWriter.java +++ b/src/main/java/org/dspace/pack/bagit/BagItAipWriter.java @@ -23,17 +23,19 @@ import java.sql.SQLException; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; -import javax.xml.bind.Marshaller; import com.google.common.io.CountingOutputStream; +import jakarta.xml.bind.JAXBContext; +import jakarta.xml.bind.JAXBException; +import jakarta.xml.bind.Marshaller; import org.apache.commons.io.FileUtils; import org.dspace.authorize.AuthorizeException; import org.dspace.content.Bitstream; +import org.dspace.content.Item; import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.core.Context; @@ -53,6 +55,7 @@ import org.joda.time.LocalDate; import org.joda.time.format.ISODateTimeFormat; + /** * The BagItAipWriter handles the packaging of DSpaceObjects into their respective bags. It processes the metadata and * bitstreams given to it by the various {@link org.dspace.pack.Packer}s in order to write the object.properties, @@ -79,12 +82,14 @@ public class BagItAipWriter { public static final String TEMPLATE_XML = "template-metadata.xml"; private static final String BITSTREAM_PREFIX = "bitstream_"; + protected static final long DEFAULT_MODIFIED_DATE = 1036368000L * 1000; + private final BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService(); - // Fields used for book keeping + // Fields used for bookkeeping private final AtomicLong successBytes = new AtomicLong(); private final AtomicLong successFiles = new AtomicLong(); - private final Map checksums = new HashMap<>(); + private final LinkedHashMap checksums = new LinkedHashMap<>(); /** * The context to use diff --git a/src/main/java/org/dspace/pack/bagit/BagItPolicyUtil.java b/src/main/java/org/dspace/pack/bagit/BagItPolicyUtil.java index 238b3295..16606023 100644 --- a/src/main/java/org/dspace/pack/bagit/BagItPolicyUtil.java +++ b/src/main/java/org/dspace/pack/bagit/BagItPolicyUtil.java @@ -49,6 +49,11 @@ public class BagItPolicyUtil { private static final Logger logger = LoggerFactory.getLogger(BagItPolicyUtil.class); + /** + * Private constructor for this utility class + */ + private BagItPolicyUtil() {} + /** * Create a {@link Policy} for a {@link DSpaceObject} * @@ -134,7 +139,45 @@ public static void registerPolicies(final Context context, final DSpaceObject dS // then use the authorizationService to add all policies to the dso final List resourcePolicies = new ArrayList<>(); for (Policy policy : policies.getPolicies()) { - final ResourcePolicy resourcePolicy = resourcePolicyService.create(context); + EPerson ePerson = null; + Group group = null; + + final String groupName = policy.getGroup(); + final String ePersonEmail = policy.getEperson(); + + if (groupName != null) { + final String nameForImport; + + if (groupName.equalsIgnoreCase(Group.ADMIN) || groupName.equalsIgnoreCase(Group.ANONYMOUS)) { + nameForImport = groupName; + } else { + nameForImport = PackageUtils.translateGroupNameForImport(context, groupName); + } + + group = groupService.findByName(context, nameForImport); + if (group == null) { + logger.warn("Could not find group {}} in the database! If this" + + "is either the ADMIN or ANONYMOUS group check that your database is" + + "initialized correctly.", nameForImport); + } + } else if (ePersonEmail != null) { + ePerson = ePersonService.findByEmail(context, ePersonEmail); + if (ePerson == null) { + logger.warn("Could not find ePerson {} in the database!", ePersonEmail); + } + } + + // ResourcePolicy requires either a Group or an EPerson + if (ePerson == null && group == null) { + throw new PackageException("ResourcePolicy requires either a Group or an EPerson. Neither were found."); + } + + final ResourcePolicy resourcePolicy = resourcePolicyService.create(context, ePerson, group); + if (resourcePolicy == null) { + throw new PackageException("Unable to create a ResourcePolicy."); + } + + // Set remaining ResourcePolicy fields resourcePolicy.setdSpaceObject(dSpaceObject); final String rpName = policy.getName(); @@ -167,37 +210,6 @@ public static void registerPolicies(final Context context, final DSpaceObject dS } } - final String groupName = policy.getGroup(); - final String epersonEmail = policy.getEperson(); - if (groupName != null) { - final String nameForImport; - - if (groupName.equalsIgnoreCase(Group.ADMIN) || groupName.equalsIgnoreCase(Group.ANONYMOUS)) { - nameForImport = groupName; - } else { - nameForImport = PackageUtils.translateGroupNameForImport(context, groupName); - } - - final Group group = groupService.findByName(context, nameForImport); - if (group == null) { - throw new PackageException("Could not find group " + nameForImport + " in the database! If this" + - "is either the ADMIN or ANONYMOUS group check that your database is" + - "initialized correctly."); - } - - resourcePolicy.setGroup(group); - } else if (epersonEmail != null) { - final EPerson ePerson = ePersonService.findByEmail(context, epersonEmail); - if (ePerson == null) { - throw new PackageException("Could not find ePerson " + epersonEmail + " in the database!"); - } - - resourcePolicy.setEPerson(ePerson); - } else { - // throw an exception as well? - logger.warn("Cannot import policy, no rp-group or rp-eperson attribute found on value!"); - } - final Integer action = actionMapper().get(policy.getAction()); // exception if null? if (action != null) { diff --git a/src/main/java/org/dspace/pack/bagit/BagItRolesUtil.java b/src/main/java/org/dspace/pack/bagit/BagItRolesUtil.java index a3baa36a..e1951c5b 100644 --- a/src/main/java/org/dspace/pack/bagit/BagItRolesUtil.java +++ b/src/main/java/org/dspace/pack/bagit/BagItRolesUtil.java @@ -41,6 +41,11 @@ */ public class BagItRolesUtil { + /** + * Private constructor for this utility class + */ + private BagItRolesUtil() {} + /** * Retrieve all roles in a DSpace site. Gets all {@link Group}s and {@link EPerson}s. * @@ -53,7 +58,7 @@ public class BagItRolesUtil { public static DSpaceRoles getDSpaceRoles(final Context context, final Site site) throws SQLException, PackageException { final GroupService groupService = EPersonServiceFactory.getInstance().getGroupService(); - final EPersonService ePersonService= EPersonServiceFactory.getInstance().getEPersonService(); + final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); final DSpaceRoles dSpaceRoles = new DSpaceRoles(); diff --git a/src/main/java/org/dspace/pack/bagit/CatalogPacker.java b/src/main/java/org/dspace/pack/bagit/CatalogPacker.java index 7271709a..aef4a861 100644 --- a/src/main/java/org/dspace/pack/bagit/CatalogPacker.java +++ b/src/main/java/org/dspace/pack/bagit/CatalogPacker.java @@ -39,8 +39,7 @@ * * @author richardrodgers */ -public class CatalogPacker implements Packer -{ +public class CatalogPacker implements Packer { private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); private final Context context; @@ -50,27 +49,23 @@ public class CatalogPacker implements Packer // Package compression format (e.g. zip or tgz) - Catalog packer uses same as AIPs private String archFmt = configurationService.getProperty("replicate.packer.archfmt"); - public CatalogPacker(Context context, String objectId) - { + public CatalogPacker(Context context, String objectId) { this.context = context; this.objectId = objectId; } - - public CatalogPacker(Context context, String objectId, String ownerId, List members) - { + + public CatalogPacker(Context context, String objectId, String ownerId, List members) { this.context = context; this.objectId = objectId; this.ownerId = ownerId; this.members = members; } - public String getOwnerId() - { + public String getOwnerId() { return ownerId; } - public List getMembers() - { + public List getMembers() { return members; } @@ -89,7 +84,7 @@ public File pack(File packDir) throws IOException, SQLException, AuthorizeExcept properties.put(OBJFILE, objectProperties); // members file - if (members.size() > 0) { + if (!members.isEmpty()) { properties.put("members", members); } @@ -114,21 +109,18 @@ public void unpack(File archive) throws IOException { } @Override - public long size(String method) - { + public long size(String method) { // not currently implemented return 0L; } @Override - public void setContentFilter(String filter) - { + public void setContentFilter(String filter) { // no-op } @Override - public void setReferenceFilter(String filter) - { + public void setReferenceFilter(String filter) { throw new UnsupportedOperationException("Not supported yet."); } } diff --git a/src/main/java/org/dspace/pack/bagit/CollectionPacker.java b/src/main/java/org/dspace/pack/bagit/CollectionPacker.java index a70d898f..985fbb09 100644 --- a/src/main/java/org/dspace/pack/bagit/CollectionPacker.java +++ b/src/main/java/org/dspace/pack/bagit/CollectionPacker.java @@ -53,15 +53,13 @@ * * @author richardrodgers */ -public class CollectionPacker implements Packer -{ +public class CollectionPacker implements Packer { private CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); // NB - these values must remain synchronized with DB schema // they represent the persistent object state - private static final String[] fields = - { + private static final String[] fields = { "name", "short_description", "introductory_text", @@ -75,20 +73,17 @@ public class CollectionPacker implements Packer private Collection collection = null; private String archFmt = null; - public CollectionPacker(Context context, Collection collection, String archFmt) - { + public CollectionPacker(Context context, Collection collection, String archFmt) { this.context = context; this.collection = collection; this.archFmt = archFmt; } - public Collection getCollection() - { + public Collection getCollection() { return collection; } - public void setCollection(Collection collection) - { + public void setCollection(Collection collection) { this.collection = collection; } @@ -200,45 +195,40 @@ public void unpack(File archive) throws AuthorizeException, IOException, SQLExce } @Override - public long size(String method) throws SQLException - { + public long size(String method) throws SQLException { long size = 0L; + // start with logo size, if present Bitstream logo = collection.getLogo(); - if (logo != null) - { + if (logo != null) { size += logo.getSizeBytes(); } + // proceed to items, unless 'norecurse' set - if (! "norecurse".equals(method)) - { + if (!"norecurse".equals(method)) { Iterator itemIter = itemService.findByCollection(context, collection); ItemPacker iPup = null; - while (itemIter.hasNext()) - { - if (iPup == null) - { + while (itemIter.hasNext()) { + if (iPup == null) { iPup = (ItemPacker)PackerFactory.instance(context, itemIter.next()); - } - else - { + } else { iPup.setItem(itemIter.next()); } + size += iPup.size(method); } } + return size; } @Override - public void setContentFilter(String filter) - { + public void setContentFilter(String filter) { // no-op } @Override - public void setReferenceFilter(String filter) - { + public void setReferenceFilter(String filter) { throw new UnsupportedOperationException("Not supported yet."); } diff --git a/src/main/java/org/dspace/pack/bagit/CommunityPacker.java b/src/main/java/org/dspace/pack/bagit/CommunityPacker.java index 860591e2..5f1db86d 100644 --- a/src/main/java/org/dspace/pack/bagit/CommunityPacker.java +++ b/src/main/java/org/dspace/pack/bagit/CommunityPacker.java @@ -49,8 +49,7 @@ * * @author richardrodgers */ -public class CommunityPacker implements Packer -{ +public class CommunityPacker implements Packer { private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); // NB - these values must remain synchronized with DB schema - @@ -67,20 +66,17 @@ public class CommunityPacker implements Packer private Community community = null; private String archFmt = null; - public CommunityPacker(Context context, Community community, String archFmt) - { + public CommunityPacker(Context context, Community community, String archFmt) { this.context = context; this.community = community; this.archFmt = archFmt; } - public Community getCommunity() - { + public Community getCommunity() { return community; } - public void setCommunity(Community community) - { + public void setCommunity(Community community) { this.community = community; } @@ -110,7 +106,7 @@ public File pack(File packDir) throws AuthorizeException, SQLException, IOExcept // collect the policy final Policies policy = BagItPolicyUtil.getPolicy(context, community); - // and finally get he roles + // and finally get the roles DSpaceRoles dSpaceRoles = null; try { dSpaceRoles = BagItRolesUtil.getDSpaceRoles(context, community); @@ -148,7 +144,7 @@ public void unpack(File archive) throws AuthorizeException, IOException, SQLExce throw new IOException(e.getMessage(), e); } - final Metadata metadata= reader.readMetadata(); + final Metadata metadata = reader.readMetadata(); for (Value value : metadata.getValues()) { MetadataFieldName field = value.getMetadataField(); communityService.setMetadataSingleValue(context, community, field.schema, field.element, field.qualifier, @@ -168,39 +164,35 @@ public void unpack(File archive) throws AuthorizeException, IOException, SQLExce } @Override - public long size(String method) throws SQLException - { + public long size(String method) throws SQLException { long size = 0L; + // logo size, if present Bitstream logo = community.getLogo(); - if (logo != null) - { + if (logo != null) { size += logo.getSizeBytes(); } + // proceed to children, unless 'norecurse' set - if (! "norecurse".equals(method)) - { - for (Community comm : community.getSubcommunities()) - { + if (!"norecurse".equals(method)) { + for (Community comm : community.getSubcommunities()) { size += PackerFactory.instance(context, comm).size(method); } - for (Collection coll : community.getCollections()) - { + for (Collection coll : community.getCollections()) { size += PackerFactory.instance(context, coll).size(method); } } + return size; } @Override - public void setContentFilter(String filter) - { + public void setContentFilter(String filter) { // no-op } @Override - public void setReferenceFilter(String filter) - { + public void setReferenceFilter(String filter) { throw new UnsupportedOperationException("Not supported yet."); } diff --git a/src/main/java/org/dspace/pack/bagit/ItemPacker.java b/src/main/java/org/dspace/pack/bagit/ItemPacker.java index 94499e8f..7e8cfa45 100644 --- a/src/main/java/org/dspace/pack/bagit/ItemPacker.java +++ b/src/main/java/org/dspace/pack/bagit/ItemPacker.java @@ -69,20 +69,17 @@ public class ItemPacker implements Packer { private boolean exclude = true; private List refFilters = new ArrayList<>(); - public ItemPacker(Context context, Item item, String archFmt) - { + public ItemPacker(Context context, Item item, String archFmt) { this.context = context; this.item = item; this.archFmt = archFmt; } - public Item getItem() - { + public Item getItem() { return item; } - public void setItem(Item item) - { + public void setItem(Item item) { this.item = item; } @@ -102,7 +99,7 @@ public File pack(final File packDir) throws AuthorizeException, IOException, SQL linked.append(coll.getHandle()).append(","); } } - if (linked.length() > 0) { + if (!linked.isEmpty()) { objectProperties.add(OTHER_IDS + PROPERTIES_DELIMITER + linked.substring(0, linked.length() - 1)); } if (item.isWithdrawn()) { @@ -120,7 +117,7 @@ public File pack(final File packDir) throws AuthorizeException, IOException, SQL // policy.xml final Policies policy = BagItPolicyUtil.getPolicy(context, item); - // proceed to bundles, in sub-directories, filtering + // proceed to bundles, in subdirectories, filtering final List bitstreams = new ArrayList<>(); for (Bundle bundle : item.getBundles()) { final String bundleName = bundle.getName(); @@ -232,81 +229,69 @@ public void unpack(File archive) throws AuthorizeException, IOException, SQLExce } @Override - public long size(String method) throws SQLException - { + public long size(String method) throws SQLException { long size = 0L; + // just total bitstream sizes, respecting filters - for (Bundle bundle : item.getBundles()) - { - if (accept(bundle.getName())) - { - for (Bitstream bs : bundle.getBitstreams()) - { + for (Bundle bundle : item.getBundles()) { + if (accept(bundle.getName())) { + for (Bitstream bs : bundle.getBitstreams()) { size += bs.getSizeBytes(); } } } + return size; } - + @Override - public void setContentFilter(String filter) - { - //If our filter list of bundles begins with a '+', then this list - // specifies all the bundles to *include*. Otherwise all + public void setContentFilter(String filter) { + // If our filter list of bundles begins with a '+', then this list + // specifies all the bundles to *include*. Otherwise all // bundles *except* the listed ones are included - if(filter.startsWith("+")) - { + if (filter.startsWith("+")) { exclude = false; - //remove the preceding '+' from our bundle list + // remove the preceding '+' from our bundle list filter = filter.substring(1); } - + filterBundles = Arrays.asList(filter.split(",")); } - private boolean accept(String name) - { + private boolean accept(String name) { boolean onList = filterBundles.contains(name); return exclude ? ! onList : onList; } @Override - public void setReferenceFilter(String filterSet) - { + public void setReferenceFilter(String filterSet) { // parse ref filter list - for (String filter : filterSet.split(",")) - { + for (String filter : filterSet.split(",")) { refFilters.add(new RefFilter(filter)); } } - private String byReference(Bundle bundle, Bitstream bs) - { - for (RefFilter filter : refFilters) - { + private String byReference(Bundle bundle, Bitstream bs) { + for (RefFilter filter : refFilters) { if (filter.bundle.equals(bundle.getName()) && - filter.size == bs.getSizeBytes()) - { + filter.size == bs.getSizeBytes()) { return filter.url; } } + return null; } - private class RefFilter - { + private class RefFilter { public String bundle; public long size; public String url; - public RefFilter(String filter) - { + public RefFilter(String filter) { String[] parts = filter.split(" "); bundle = parts[0]; - size = Long.valueOf(parts[1]); + size = Long.parseLong(parts[1]); url = parts[2]; } } - } diff --git a/src/main/java/org/dspace/pack/bagit/SitePacker.java b/src/main/java/org/dspace/pack/bagit/SitePacker.java index 44cdf371..bf4789d0 100644 --- a/src/main/java/org/dspace/pack/bagit/SitePacker.java +++ b/src/main/java/org/dspace/pack/bagit/SitePacker.java @@ -66,6 +66,7 @@ public SitePacker(Context context, Site site, String archFmt) { @Override public File pack(File packDir) throws AuthorizeException, IOException, SQLException { final Map> properties = new HashMap<>(); + // object.properties final List objectProperties = new ArrayList<>(); objectProperties.add(BAG_TYPE + PROPERTIES_DELIMITER + BAG_AIP); diff --git a/src/main/java/org/dspace/pack/bagit/xml/metadata/Metadata.java b/src/main/java/org/dspace/pack/bagit/xml/metadata/Metadata.java index 6ca816c7..1b42af57 100644 --- a/src/main/java/org/dspace/pack/bagit/xml/metadata/Metadata.java +++ b/src/main/java/org/dspace/pack/bagit/xml/metadata/Metadata.java @@ -9,8 +9,9 @@ import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; /** * Root tag for metadata.xml. Contains only a list of metadata {@link Value}s. diff --git a/src/main/java/org/dspace/pack/bagit/xml/metadata/Value.java b/src/main/java/org/dspace/pack/bagit/xml/metadata/Value.java index c903d21d..e735ed15 100644 --- a/src/main/java/org/dspace/pack/bagit/xml/metadata/Value.java +++ b/src/main/java/org/dspace/pack/bagit/xml/metadata/Value.java @@ -21,9 +21,8 @@ import static org.dspace.eperson.service.EPersonService.MD_LASTNAME; import static org.dspace.eperson.service.EPersonService.MD_PHONE; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlValue; - +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlValue; import org.dspace.content.MetadataFieldName; import org.dspace.content.MetadataValue; diff --git a/src/main/java/org/dspace/pack/bagit/xml/policy/Policies.java b/src/main/java/org/dspace/pack/bagit/xml/policy/Policies.java index a58b2b05..d7ca8552 100644 --- a/src/main/java/org/dspace/pack/bagit/xml/policy/Policies.java +++ b/src/main/java/org/dspace/pack/bagit/xml/policy/Policies.java @@ -9,8 +9,9 @@ import java.util.ArrayList; import java.util.List; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlRootElement; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlRootElement; /** * Root element for policy.xml. Contains only a list of {@link Policy} objects. diff --git a/src/main/java/org/dspace/pack/bagit/xml/policy/Policy.java b/src/main/java/org/dspace/pack/bagit/xml/policy/Policy.java index c4a36227..89ff8beb 100644 --- a/src/main/java/org/dspace/pack/bagit/xml/policy/Policy.java +++ b/src/main/java/org/dspace/pack/bagit/xml/policy/Policy.java @@ -7,7 +7,7 @@ */ package org.dspace.pack.bagit.xml.policy; -import javax.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlAttribute; /** * Pojo for {@link org.dspace.authorize.ResourcePolicy} objects diff --git a/src/main/java/org/dspace/pack/bagit/xml/roles/AssociatedGroup.java b/src/main/java/org/dspace/pack/bagit/xml/roles/AssociatedGroup.java index bde26f63..0cffced9 100644 --- a/src/main/java/org/dspace/pack/bagit/xml/roles/AssociatedGroup.java +++ b/src/main/java/org/dspace/pack/bagit/xml/roles/AssociatedGroup.java @@ -11,10 +11,10 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementWrapper; +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElementWrapper; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.DSpaceObject; diff --git a/src/main/java/org/dspace/pack/bagit/xml/roles/DSpaceRoles.java b/src/main/java/org/dspace/pack/bagit/xml/roles/DSpaceRoles.java index 08ac3e5f..8bfedf82 100644 --- a/src/main/java/org/dspace/pack/bagit/xml/roles/DSpaceRoles.java +++ b/src/main/java/org/dspace/pack/bagit/xml/roles/DSpaceRoles.java @@ -9,9 +9,10 @@ import java.util.HashSet; import java.util.Set; -import javax.xml.bind.annotation.XmlElement; -import javax.xml.bind.annotation.XmlElementWrapper; -import javax.xml.bind.annotation.XmlRootElement; + +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElementWrapper; +import jakarta.xml.bind.annotation.XmlRootElement; /** * Top level object for the DSpaceRoles xml schema mapping diff --git a/src/main/java/org/dspace/pack/bagit/xml/roles/Member.java b/src/main/java/org/dspace/pack/bagit/xml/roles/Member.java index cca9e136..0bfe4b4e 100644 --- a/src/main/java/org/dspace/pack/bagit/xml/roles/Member.java +++ b/src/main/java/org/dspace/pack/bagit/xml/roles/Member.java @@ -7,8 +7,7 @@ */ package org.dspace.pack.bagit.xml.roles; -import javax.xml.bind.annotation.XmlAttribute; - +import jakarta.xml.bind.annotation.XmlAttribute; import org.dspace.content.packager.PackageException; import org.dspace.content.packager.PackageUtils; import org.dspace.core.Context; diff --git a/src/main/java/org/dspace/pack/bagit/xml/roles/Person.java b/src/main/java/org/dspace/pack/bagit/xml/roles/Person.java index 376bf3dd..27c13cf0 100644 --- a/src/main/java/org/dspace/pack/bagit/xml/roles/Person.java +++ b/src/main/java/org/dspace/pack/bagit/xml/roles/Person.java @@ -7,9 +7,8 @@ */ package org.dspace.pack.bagit.xml.roles; -import javax.xml.bind.annotation.XmlAttribute; -import javax.xml.bind.annotation.XmlElement; - +import jakarta.xml.bind.annotation.XmlAttribute; +import jakarta.xml.bind.annotation.XmlElement; import org.dspace.eperson.EPerson; /** diff --git a/src/main/java/org/dspace/pack/mets/METSPacker.java b/src/main/java/org/dspace/pack/mets/METSPacker.java index c56229d3..52ec6078 100644 --- a/src/main/java/org/dspace/pack/mets/METSPacker.java +++ b/src/main/java/org/dspace/pack/mets/METSPacker.java @@ -45,8 +45,7 @@ * * @author richardrodgers */ -public class METSPacker implements Packer -{ +public class METSPacker implements Packer { private PluginService pluginService = CoreServiceFactory.getInstance().getPluginService(); private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); private ItemService itemService = ContentServiceFactory.getInstance().getItemService(); @@ -73,15 +72,13 @@ public class METSPacker implements Packer private PackageDisseminator dip = null; private PackageIngester sip = null; - public METSPacker(Context context, String archFmt) - { + public METSPacker(Context context, String archFmt) { this.context = context; this.dso = null; this.archFmt = archFmt; } - public METSPacker(Context context, DSpaceObject dso, String archFmt) - { + public METSPacker(Context context, DSpaceObject dso, String archFmt) { this.context = context; this.dso = dso; this.archFmt = archFmt; @@ -99,8 +96,7 @@ public void setContext(Context context) { * Get DSpaceObject we are working with * @return dso DSpaceObject */ - public DSpaceObject getDSO() - { + public DSpaceObject getDSO() { return dso; } @@ -108,8 +104,7 @@ public DSpaceObject getDSO() * Set DSpaceObject we are working with * @param dso DSpaceObject */ - public void setDSO(DSpaceObject dso) - { + public void setDSO(DSpaceObject dso) { this.dso = dso; } @@ -123,41 +118,34 @@ public void setDSO(DSpaceObject dso) * @throws SQLException if database error */ @Override - public File pack(File packDir) throws AuthorizeException, IOException, SQLException - { - //retrieve specified package disseminator - if (dip == null) - { + public File pack(File packDir) throws AuthorizeException, IOException, SQLException { + // retrieve specified package disseminator + if (dip == null) { dip = (PackageDisseminator) pluginService. getNamedPlugin(PackageDisseminator.class, "AIP"); } - if (dip == null) - { + + if (dip == null) { throw new IOException("Cannot obtain AIP disseminator. No dissemination plugin named 'AIP' is configured."); } - //Initialize packaging params + // Initialize packaging params PackageParameters pkgParams = new PackageParameters(); - //If a content (Bundle) filter is specified - if(this.contentFilter!=null && !this.contentFilter.isEmpty()) - { - //Pass that on to the 'filterBundles' package parameter (which uses the same syntax) + // If a content (Bundle) filter is specified + if (this.contentFilter != null && !this.contentFilter.isEmpty()) { + // Pass that on to the 'filterBundles' package parameter (which uses the same syntax) pkgParams.addProperty("filterBundles", contentFilter); } File archive = new File(packDir.getParentFile(), packDir.getName() + "." + archFmt); - //disseminate the requested object - try - { + + // disseminate the requested object + try { dip.disseminate(context, dso, pkgParams, archive); - } - catch (PackageException pkgE) - { + } catch (PackageException pkgE) { throw new IOException(pkgE.getMessage(), pkgE); - } - catch (CrosswalkException xwkE) - { + } catch (CrosswalkException xwkE) { throw new IOException(xwkE.getMessage(), xwkE); } @@ -174,13 +162,11 @@ public File pack(File packDir) throws AuthorizeException, IOException, SQLExcept * @throws SQLException if database error */ @Override - public void unpack(File archive) throws AuthorizeException, IOException, SQLException - { - //unpack with default PackageParameter settings + public void unpack(File archive) throws AuthorizeException, IOException, SQLException { + // unpack with default PackageParameter settings unpack(archive, null); } - /** * Restore/Replace a *single* DSpaceObject based on the contents of a METS AIP Package, * and the given PackageParameters. This uses the configured AIP PackageIngester @@ -197,118 +183,104 @@ public void unpack(File archive) throws AuthorizeException, IOException, SQLExce * @throws IOException if I/O error * @throws SQLException if database error */ - public void unpack(File archive, PackageParameters pkgParams) throws AuthorizeException, IOException, SQLException - { + public void unpack(File archive, PackageParameters pkgParams) throws AuthorizeException, IOException, SQLException { if (archive == null || ! archive.exists()) { throw new IOException("Missing archive for object: " + dso.getHandle()); } - if (sip == null) - { + + if (sip == null) { sip = (PackageIngester) pluginService .getNamedPlugin(PackageIngester.class, "AIP"); } - if (sip == null) - { + + if (sip == null) { throw new IOException("Cannot obtain AIP ingester. No ingestion plugin named 'AIP' is configured."); } - if(pkgParams==null || pkgParams.isEmpty()) - { + if (pkgParams == null || pkgParams.isEmpty()) { pkgParams = new PackageParameters(); //--- Default settings/parameters for PackageIngester -- // These default settings should work for a wide variety of replace/restore actions. // For more info, see: https://wiki.duraspace.org/display/DSDOC18/AIP+Backup+and+Restore - //Always run in Replace mode (always replace existing objects & restore ones that are missing) + // Always run in Replace mode (always replace existing objects & restore ones that are missing) pkgParams.setReplaceModeEnabled(true); - //Always run in Recursive mode (also replace/restore all child objects) + + // Always run in Recursive mode (also replace/restore all child objects) pkgParams.setRecursiveModeEnabled(true); - //Always create Metadata Fields referenced in an AIP, which are found to be missing in DSpace + + // Always create Metadata Fields referenced in an AIP, which are found to be missing in DSpace pkgParams.setProperty("createMetadataFields", "true"); - //Always skip over an object if it's Parent Object is "missing". These errors will still be logged as warnings. - //(This setting is recommended for 'recursive' mode, as sometimes ingester will try to restore a child object - // before its parent. But, once parent is restored, the child object will then be restored immediately after) + + // Always skip over an object if it's Parent Object is "missing". These errors will still be + // logged as warnings. (This setting is recommended for 'recursive' mode, as sometimes ingester + // will try to restore a child object before its parent. But, once parent is restored, the child + // object will then be restored immediately after) pkgParams.setProperty("skipIfParentMissing", "true"); } DSpaceObject updatedDso = null; - try - { + try { // Because we may be unpacking AIPs from an external storage location (e.g. DuraCloud or mapped drive) // we will only ever replace/restore a SINGLE OBJECT at a time. // It is up to the Replication Task to ensure each item is downloaded as needed and its // children are also replaced/restored recursively as needed. - if(pkgParams.replaceModeEnabled()) //run object replace + if (pkgParams.replaceModeEnabled()) { + // run object replace updatedDso = sip.replace(context, dso, archive, pkgParams); - else //else run a 'restore' (special form of ingest) with a null parent object (parent obj will be determined from package manifest) + } else { + // else run a 'restore' (special form of ingest) with a null parent object + // (parent obj will be determined from package manifest) updatedDso = sip.ingest(context, null, archive, pkgParams, null); - } - catch(IllegalStateException ie) - { + } + } catch (IllegalStateException isE) { // NOTE: we should only encounter an IllegalStateException, when // attempting to ingest an object that already exists in the system. // (i.e. this is a "handle already in use" exception) - //if we are skipping over (i.e. keeping) existing objects - if(pkgParams.keepExistingModeEnabled()) - { - //just log a warning + // if we are skipping over (i.e. keeping) existing objects + if (pkgParams.keepExistingModeEnabled()) { + // just log a warning log.warn("Skipping over object which already exists."); + } else { + // Pass this exception on -- which essentially causes a full rollback + // of all changes (this is the default) + throw isE; } - else // Pass this exception on -- which essentially causes a full rollback of all changes (this is the default) - { - throw ie; - } - } - catch (PackageException pkgE) - { + } catch (PackageException pkgE) { throw new IOException(pkgE.getMessage(), pkgE); - } - catch (CrosswalkException xwkE) - { + } catch (CrosswalkException xwkE) { throw new IOException(xwkE.getMessage(), xwkE); - } - catch (WorkflowException wfE) - { + } catch (WorkflowException wfE) { throw new IOException(wfE.getMessage(), wfE); } - //If we are using a class that extends AbstractPackageIngester, - //then we can save the child AIP references for later processing. - //(When recursion is enabled, this step ensures the calling curation task + // If we are using a class that extends AbstractPackageIngester, + // then we can save the child AIP references for later processing. + // (When recursion is enabled, this step ensures the calling curation task // knows which child AIPs to next restore/replace) - if(sip instanceof AbstractPackageIngester) - { - //Only non-Items reference other child AIPs - //(NOTE: Items have no children, as Bitstreams/Bundles are contained in Item packages) - if(updatedDso!=null && updatedDso.getType()!=Constants.ITEM) - { - //Check if we found child package references when unpacking this latest package into a DSpaceObject + if (sip instanceof AbstractPackageIngester) { + // Only non-Items reference other child AIPs + // (NOTE: Items have no children, as Bitstreams/Bundles are contained in Item packages) + if (updatedDso != null && updatedDso.getType() != Constants.ITEM) { + // Check if we found child package references when unpacking this latest package into a DSpaceObject this.childPackageRefs = ((AbstractPackageIngester) sip).getPackageReferences(updatedDso); - }//end if not an Item + } } - //NOTE: Context is handled by Curator -- it will commit or close when needed. + // NOTE: Context is handled by Curator -- it will commit or close when needed. } @Override - public long size(String method) throws SQLException - { + public long size(String method) throws SQLException { int type = dso.getType(); - if (Constants.SITE == type) - { + if (Constants.SITE == type) { return siteSize(); - } - else if (Constants.COMMUNITY == type) - { + } else if (Constants.COMMUNITY == type) { return communitySize((Community)dso); - } - else if (Constants.COLLECTION == type) - { + } else if (Constants.COLLECTION == type) { return collectionSize((Collection)dso); - } - else - { + } else { return itemSize((Item)dso); } } @@ -322,16 +294,14 @@ else if (Constants.COLLECTION == type) * @return estimated storage size * @throws SQLException if database error */ - private long siteSize() throws SQLException - { + private long siteSize() throws SQLException { long size = 0L; - //This Site AIP itself is very small, so as a "guess" we'll just total + // This Site AIP itself is very small, so as a "guess" we'll just total // up the size of all Community, Collection & Item AIPs - //Then, perform this task for all Top-Level Communities in the Site + // Then, perform this task for all Top-Level Communities in the Site // (this will recursively perform task for all objects in DSpace) - for (Community subcomm : communityService.findAllTop(context)) - { + for (Community subcomm : communityService.findAllTop(context)) { size += communitySize(subcomm); } @@ -348,23 +318,25 @@ private long siteSize() throws SQLException * @return estimated storage size * @throws SQLException if database error */ - private long communitySize(Community community) throws SQLException - { + private long communitySize(Community community) throws SQLException { long size = 0L; + // logo size, if present Bitstream logo = community.getLogo(); - if (logo != null) - { + if (logo != null) { size += logo.getSizeBytes(); } - for (Community comm : community.getSubcommunities()) - { + + // Calculate sub-communities + for (Community comm : community.getSubcommunities()) { size += communitySize(comm); } - for (Collection coll : community.getCollections()) - { + + // Calculate collections + for (Collection coll : community.getCollections()) { size += collectionSize(coll); } + return size; } @@ -378,20 +350,21 @@ private long communitySize(Community community) throws SQLException * @return estimated storage size * @throws SQLException if database error */ - private long collectionSize(Collection collection) throws SQLException - { + private long collectionSize(Collection collection) throws SQLException { long size = 0L; + // start with logo size, if present Bitstream logo = collection.getLogo(); - if (logo != null) - { + if (logo != null) { size += logo.getSizeBytes(); } + + // Calculate items Iterator itemIter = itemService.findByCollection(context, collection); - while (itemIter.hasNext()) - { + while (itemIter.hasNext()) { size += itemSize(itemIter.next()); } + return size; } @@ -404,33 +377,29 @@ private long collectionSize(Collection collection) throws SQLException * @return estimated storage size * @throws SQLException if database error */ - private long itemSize(Item item) throws SQLException - { + private long itemSize(Item item) throws SQLException { long size = 0L; + // just total bitstream sizes, respecting filters - for (Bundle bundle : item.getBundles()) - { - if (includedBundle(bundle.getName())) - { - for (Bitstream bs : bundle.getBitstreams()) - { + for (Bundle bundle : item.getBundles()) { + if (includedBundle(bundle.getName())) { + for (Bitstream bs : bundle.getBitstreams()) { size += bs.getSizeBytes(); } } } + return size; } @Override - public void setContentFilter(String filter) - { - //If our filter list of bundles begins with a '+', then this list + public void setContentFilter(String filter) { + // If our filter list of bundles begins with a '+', then this list // specifies all the bundles to *include*. Otherwise all // bundles *except* the listed ones are included - if(filter.startsWith("+")) - { + if (filter.startsWith("+")) { exclude = false; - //remove the preceding '+' from our bundle list + // remove the preceding '+' from our bundle list filter = filter.substring(1); } @@ -438,15 +407,13 @@ public void setContentFilter(String filter) filterBundles = Arrays.asList(filter.split(",")); } - private boolean includedBundle(String name) - { + private boolean includedBundle(String name) { boolean onList = filterBundles.contains(name); return exclude ? ! onList : onList; } @Override - public void setReferenceFilter(String filterSet) - { + public void setReferenceFilter(String filterSet) { throw new UnsupportedOperationException("Not supported yet."); } @@ -459,8 +426,7 @@ public void setReferenceFilter(String filterSet) * * @return List of references to child AIPs */ - public List getChildPackageRefs() - { + public List getChildPackageRefs() { return childPackageRefs; } } diff --git a/src/test/java/org/dspace/TestAuthorizeServiceFactory.java b/src/test/java/org/dspace/TestAuthorizeServiceFactory.java index aa8b9e3c..8c687f91 100644 --- a/src/test/java/org/dspace/TestAuthorizeServiceFactory.java +++ b/src/test/java/org/dspace/TestAuthorizeServiceFactory.java @@ -19,11 +19,9 @@ * @author mikejritter */ public class TestAuthorizeServiceFactory extends AuthorizeServiceFactory { - private final AuthorizeService authorizeService = mock(AuthorizeService.class); private final ResourcePolicyService resourcePolicyService = mock(ResourcePolicyService.class); - @Override public AuthorizeService getAuthorizeService() { return authorizeService; diff --git a/src/test/java/org/dspace/TestContentServiceFactory.java b/src/test/java/org/dspace/TestContentServiceFactory.java index 1c6d46a8..f393ad80 100644 --- a/src/test/java/org/dspace/TestContentServiceFactory.java +++ b/src/test/java/org/dspace/TestContentServiceFactory.java @@ -21,6 +21,7 @@ import org.dspace.content.service.CommunityService; import org.dspace.content.service.DSpaceObjectLegacySupportService; import org.dspace.content.service.DSpaceObjectService; +import org.dspace.content.service.DuplicateDetectionService; import org.dspace.content.service.EntityService; import org.dspace.content.service.EntityTypeService; import org.dspace.content.service.InstallItemService; @@ -53,6 +54,11 @@ public class TestContentServiceFactory extends ContentServiceFactory { private final CommunityService communityService = mock(CommunityService.class); private final BundleService bundleService = mock(BundleService.class); + @Override + public DuplicateDetectionService getDuplicateDetectionService() { + throw new UnsupportedOperationException(); + }; + @Override public List> getDSpaceObjectServices() { throw new UnsupportedOperationException(); diff --git a/src/test/java/org/dspace/TestServiceManager.java b/src/test/java/org/dspace/TestServiceManager.java index cdcf54a2..2d6d044a 100644 --- a/src/test/java/org/dspace/TestServiceManager.java +++ b/src/test/java/org/dspace/TestServiceManager.java @@ -49,6 +49,11 @@ public List getServicesNames() { return new ArrayList<>(serviceNameMap.keySet()); } + @Override + public Map getServicesWithNamesByType(Class type) { + throw new UnsupportedOperationException(); + } + @Override public void registerService(String name, Object service) { serviceNameMap.put(name, service); diff --git a/src/test/java/org/dspace/ctask/replicate/store/DuraCloudObjectStoreTest.java b/src/test/java/org/dspace/ctask/replicate/store/DuraCloudObjectStoreTest.java index 6191390f..2665b405 100644 --- a/src/test/java/org/dspace/ctask/replicate/store/DuraCloudObjectStoreTest.java +++ b/src/test/java/org/dspace/ctask/replicate/store/DuraCloudObjectStoreTest.java @@ -39,7 +39,6 @@ * create outgoing requests to DuraCloud */ public class DuraCloudObjectStoreTest { - private final String group = "dc-object-store-test"; private final String mimeType = "application/zip"; @@ -55,6 +54,7 @@ public void setup() { @Test public void testUploadRetry() throws Exception { final URL root = DuraCloudObjectStoreTest.class.getClassLoader().getResource("unpack"); + // copy the file because the ObjectStore will delete it after transfer final Path catalog = Paths.get(root.toURI()).resolve("catalog.zip"); final Path zipFile = Paths.get(root.toURI()).resolve("dc-upload.zip"); @@ -95,6 +95,7 @@ public void testUploadFailure() throws Exception { objectStore.transferObject(group, zipFile.toFile()); fail("Expected transfer to fail"); } catch (IOException ignored) { + // ignore exception } // verify that the retry process was attempted @@ -108,5 +109,4 @@ public void testUploadFailure() throws Exception { // and finish cleaning up Files.delete(zipFile); } - } \ No newline at end of file diff --git a/src/test/java/org/dspace/pack/bagit/BagItPolicyUtilTest.java b/src/test/java/org/dspace/pack/bagit/BagItPolicyUtilTest.java index d06e15ff..947385b9 100644 --- a/src/test/java/org/dspace/pack/bagit/BagItPolicyUtilTest.java +++ b/src/test/java/org/dspace/pack/bagit/BagItPolicyUtilTest.java @@ -213,7 +213,8 @@ public void registerPolicies() throws Exception { final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); final ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance() .getResourcePolicyService(); - when(resourcePolicyService.create(any(Context.class))).thenReturn(initReloadable(ResourcePolicy.class)); + when(resourcePolicyService.create(any(Context.class), any(), any())) + .thenReturn(initReloadable(ResourcePolicy.class)); when(groupService.findByName(any(Context.class), eq(Group.ADMIN))).thenReturn(group); when(groupService.findByName(any(Context.class), eq(Group.ANONYMOUS))).thenReturn(group); when(ePersonService.findByEmail(any(Context.class), eq(personEmail))).thenReturn(ePerson); @@ -222,14 +223,15 @@ public void registerPolicies() throws Exception { BagItPolicyUtil.registerPolicies(mockContext, community, policy); // verify service interactions - verify(resourcePolicyService, times(8)).create(any(Context.class)); - verify(groupService, times(4)).findByName(any(Context.class), matches(Group.ADMIN + "|" + Group.ANONYMOUS)); + verify(resourcePolicyService, times(8)).create(any(Context.class), any(), any()); + verify(groupService, times(4)).findByName(any(Context.class), + matches(Group.ADMIN + "|" + Group.ANONYMOUS)); verify(ePersonService, times(4)).findByEmail(any(Context.class), eq(personEmail)); // additional verification of services which we didn't need to set up final AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService(); verify(authorizeService, times(1)).removeAllPolicies(any(Context.class), eq(community)); - verify(authorizeService, times(1)).addPolicies(any(Context.class), anyListOf(ResourcePolicy.class), - eq(community)); + verify(authorizeService, times(1)).addPolicies(any(Context.class), + anyListOf(ResourcePolicy.class), eq(community)); } } diff --git a/src/test/java/org/dspace/pack/bagit/CatalogPackerTest.java b/src/test/java/org/dspace/pack/bagit/CatalogPackerTest.java index e70730c7..04dfaea9 100644 --- a/src/test/java/org/dspace/pack/bagit/CatalogPackerTest.java +++ b/src/test/java/org/dspace/pack/bagit/CatalogPackerTest.java @@ -35,7 +35,8 @@ public void testPack() throws Exception { final Path output = Paths.get(resources.toURI().resolve("catalog-packer-test")); // setup the packer - final CatalogPacker packer = new CatalogPacker(mockContext, "object-id", "owner-id", ImmutableList.of("member")); + final CatalogPacker packer = new CatalogPacker(mockContext, "object-id", + "owner-id", ImmutableList.of("member")); final File packedOutput = packer.pack(output.toFile()); assertThat(packedOutput).exists(); diff --git a/src/test/java/org/dspace/pack/bagit/CollectionPackerTest.java b/src/test/java/org/dspace/pack/bagit/CollectionPackerTest.java index 6ffbf8eb..b1d50865 100644 --- a/src/test/java/org/dspace/pack/bagit/CollectionPackerTest.java +++ b/src/test/java/org/dspace/pack/bagit/CollectionPackerTest.java @@ -41,6 +41,8 @@ import org.dspace.content.service.CollectionService; import org.dspace.content.service.ItemService; import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.GroupService; @@ -159,7 +161,7 @@ public void testUnpack() throws Exception { // since our policy.xml is empty, verify that we never fetched anything and still used the authorize service // as expected final List empty = new ArrayList<>(); - verify(resourcePolicyService, never()).create(any(Context.class)); + verify(resourcePolicyService, never()).create(any(Context.class), any(EPerson.class), any(Group.class)); verify(groupService, never()).findByName(any(Context.class), anyString()); verify(ePersonService, never()).findByEmail(any(Context.class), anyString()); verify(authorizeService, times(1)).removeAllPolicies(any(Context.class), eq(collection)); diff --git a/src/test/java/org/dspace/pack/bagit/CommunityPackerTest.java b/src/test/java/org/dspace/pack/bagit/CommunityPackerTest.java index 9897f46e..f23be172 100644 --- a/src/test/java/org/dspace/pack/bagit/CommunityPackerTest.java +++ b/src/test/java/org/dspace/pack/bagit/CommunityPackerTest.java @@ -35,6 +35,8 @@ import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.CommunityService; import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.GroupService; @@ -126,7 +128,7 @@ public void testUnpack() throws Exception { // since our policy.xml is empty, verify that we never fetched anything and still used the authorize service // as expected final List empty = new ArrayList<>(); - verify(resourcePolicyService, never()).create(any(Context.class)); + verify(resourcePolicyService, never()).create(any(Context.class), any(EPerson.class), any(Group.class)); verify(groupService, never()).findByName(any(Context.class), anyString()); verify(ePersonService, never()).findByEmail(any(Context.class), anyString()); verify(authorizeService, times(1)).removeAllPolicies(any(Context.class), eq(community)); diff --git a/src/test/java/org/dspace/pack/bagit/ItemPackerTest.java b/src/test/java/org/dspace/pack/bagit/ItemPackerTest.java index 16e5fceb..74ca945c 100644 --- a/src/test/java/org/dspace/pack/bagit/ItemPackerTest.java +++ b/src/test/java/org/dspace/pack/bagit/ItemPackerTest.java @@ -52,6 +52,8 @@ import org.dspace.content.service.BundleService; import org.dspace.content.service.ItemService; import org.dspace.core.Context; +import org.dspace.eperson.EPerson; +import org.dspace.eperson.Group; import org.dspace.eperson.factory.EPersonServiceFactory; import org.dspace.eperson.service.EPersonService; import org.dspace.eperson.service.GroupService; @@ -329,7 +331,7 @@ public void testUnpack() throws Exception { // since our policy.xml is empty, verify that we never fetched anything and still used the authorize service // as expected final List empty = new ArrayList<>(); - verify(resourcePolicyService, never()).create(any(Context.class)); + verify(resourcePolicyService, never()).create(any(Context.class), any(EPerson.class), any(Group.class)); verify(groupService, never()).findByName(any(Context.class), anyString()); verify(ePersonService, never()).findByEmail(any(Context.class), anyString()); verify(authorizeService, times(1)).removeAllPolicies(any(Context.class), eq(item));