diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 849fbf93be..3605531adb 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -20,11 +20,8 @@ List of changes in this PR:
_This checklist provides a reminder of what we are going to look for when reviewing your PR. You need not complete this checklist prior to creating your PR (draft PRs are always welcome). If you are unsure about an item in the checklist, don't hesitate to ask. We're here to help!_
- [ ] My PR is small in size (e.g. less than 1,000 lines of code, not including comments & integration tests). Exceptions may be made if previously agreed upon.
-- [ ] My PR passes Checkstyle validation based on the [Code Style Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Style+Guide)
+- [ ] My PR passes Checkstyle validation based on the [Code Style Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Style+Guide).
- [ ] My PR includes Javadoc for _all new (or modified) public methods and classes_. It also includes Javadoc for large or complex private methods.
-- [ ] My PR passes all tests and includes new/updated Unit or Integration Tests for any bug fixes, improvements or new features. A few reminders about what constitutes good tests:
- * Include tests for different user types, including: (1) Anonymous user, (2) Logged in user (non-admin), and (3) Administrator.
- * Include tests for known error scenarios and error codes (e.g. `400 Bad Request`, `401 Unauthorized`, `403 Forbidden`, `404 Not Found`, etc)
- * For bug fixes, include a test that reproduces the bug and proves it is fixed. For clarity, it may be useful to provide the test in a separate commit from the bug fix.
+- [ ] My PR passes all tests and includes new/updated Unit or Integration Tests based on the [Code Testing Guide](https://wiki.lyrasis.org/display/DSPACE/Code+Testing+Guide).
- [ ] If my PR includes new, third-party dependencies (in any `pom.xml`), I've made sure their licenses align with the [DSpace BSD License](https://github.com/DSpace/DSpace/blob/master/LICENSE) based on the [Licensing of Contributions](https://wiki.lyrasis.org/display/DSPACE/Code+Contribution+Guidelines#CodeContributionGuidelines-LicensingofContributions) documentation.
- [ ] If my PR modifies the REST API, I've linked to the REST Contract page (or open PR) related to this change.
diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml
index c714746337..a0714c04ee 100644
--- a/dspace-api/pom.xml
+++ b/dspace-api/pom.xml
@@ -98,20 +98,6 @@
-
-
- com.mycila
- license-maven-plugin
-
-
- **/src/test/resources/**
- **/src/test/data/**
- **/.gitignore
- **/src/main/resources/rebel.xml
- src/test/data/dspaceFolder/config/spiders/**
-
-
- org.codehaus.mojo
diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java
index 55bb3fed4b..ad7824bebf 100644
--- a/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java
+++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/DSpaceCSV.java
@@ -8,14 +8,10 @@
package org.dspace.app.bulkedit;
import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
import java.io.Serializable;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -27,6 +23,7 @@ import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.dspace.authority.AuthorityValue;
import org.dspace.authority.factory.AuthorityServiceFactory;
@@ -141,18 +138,18 @@ public class DSpaceCSV implements Serializable {
/**
* Create a new instance, reading the lines in from file
*
- * @param f The file to read from
+ * @param inputStream the inputstream to read from
* @param c The DSpace Context
* @throws Exception thrown if there is an error reading or processing the file
*/
- public DSpaceCSV(File f, Context c) throws Exception {
+ public DSpaceCSV(InputStream inputStream, Context c) throws Exception {
// Initialise the class
init();
// Open the CSV file
BufferedReader input = null;
try {
- input = new BufferedReader(new InputStreamReader(new FileInputStream(f), "UTF-8"));
+ input = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
// Read the heading line
String head = input.readLine();
@@ -623,21 +620,15 @@ public class DSpaceCSV implements Serializable {
}
/**
- * Save the CSV file to the given filename
- *
- * @param filename The filename to save the CSV file to
- * @throws IOException Thrown if an error occurs when writing the file
+ * Creates and returns an InputStream from the CSV Lines in this DSpaceCSV
+ * @return The InputStream created from the CSVLines in this DSpaceCSV
*/
- public final void save(String filename) throws IOException {
- // Save the file
- BufferedWriter out = new BufferedWriter(
- new OutputStreamWriter(
- new FileOutputStream(filename), "UTF-8"));
+ public InputStream getInputStream() {
+ StringBuilder stringBuilder = new StringBuilder();
for (String csvLine : getCSVLinesAsStringArray()) {
- out.write(csvLine + "\n");
+ stringBuilder.append(csvLine + "\n");
}
- out.flush();
- out.close();
+ return IOUtils.toInputStream(stringBuilder.toString(), StandardCharsets.UTF_8);
}
/**
diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExport.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExport.java
index bc015ef5e0..2e4f333820 100644
--- a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExport.java
+++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExport.java
@@ -8,271 +8,84 @@
package org.dspace.app.bulkedit;
import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import com.google.common.collect.Iterators;
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
-import org.apache.commons.cli.PosixParser;
-import org.dspace.content.Collection;
-import org.dspace.content.Community;
-import org.dspace.content.DSpaceObject;
-import org.dspace.content.Item;
-import org.dspace.content.factory.ContentServiceFactory;
-import org.dspace.content.service.ItemService;
-import org.dspace.core.Constants;
+import org.dspace.content.service.MetadataDSpaceCsvExportService;
import org.dspace.core.Context;
-import org.dspace.handle.factory.HandleServiceFactory;
+import org.dspace.eperson.factory.EPersonServiceFactory;
+import org.dspace.eperson.service.EPersonService;
+import org.dspace.scripts.DSpaceRunnable;
+import org.dspace.utils.DSpace;
/**
* Metadata exporter to allow the batch export of metadata into a file
*
* @author Stuart Lewis
*/
-public class MetadataExport {
- /**
- * The items to export
- */
- protected Iterator toExport;
+public class MetadataExport extends DSpaceRunnable {
- protected ItemService itemService;
+ private boolean help = false;
+ private String filename = null;
+ private String handle = null;
+ private boolean exportAllMetadata = false;
+ private boolean exportAllItems = false;
- protected Context context;
+ private static final String EXPORT_CSV = "exportCSV";
- /**
- * Whether to export all metadata, or just normally edited metadata
- */
- protected boolean exportAll;
+ private MetadataDSpaceCsvExportService metadataDSpaceCsvExportService = new DSpace().getServiceManager()
+ .getServicesByType(MetadataDSpaceCsvExportService.class).get(0);
- protected MetadataExport() {
- itemService = ContentServiceFactory.getInstance().getItemService();
- }
+ private EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
- /**
- * Set up a new metadata export
- *
- * @param c The Context
- * @param toExport The ItemIterator of items to export
- * @param exportAll whether to export all metadata or not (include handle, provenance etc)
- */
- public MetadataExport(Context c, Iterator toExport, boolean exportAll) {
- itemService = ContentServiceFactory.getInstance().getItemService();
-
- // Store the export settings
- this.toExport = toExport;
- this.exportAll = exportAll;
- this.context = c;
- }
-
- /**
- * Method to export a community (and sub-communities and collections)
- *
- * @param c The Context
- * @param toExport The Community to export
- * @param exportAll whether to export all metadata or not (include handle, provenance etc)
- */
- public MetadataExport(Context c, Community toExport, boolean exportAll) {
- itemService = ContentServiceFactory.getInstance().getItemService();
+ @Override
+ public void internalRun() throws Exception {
+ if (help) {
+ handler.logInfo("\nfull export: metadata-export -f filename");
+ handler.logInfo("partial export: metadata-export -i handle -f filename");
+ printHelp();
+ return;
+ }
+ Context context = new Context();
+ context.turnOffAuthorisationSystem();
try {
- // Try to export the community
- this.toExport = buildFromCommunity(c, toExport, 0);
- this.exportAll = exportAll;
- this.context = c;
- } catch (SQLException sqle) {
- // Something went wrong...
- System.err.println("Error running exporter:");
- sqle.printStackTrace(System.err);
- System.exit(1);
+ context.setCurrentUser(ePersonService.find(context, this.getEpersonIdentifier()));
+ } catch (SQLException e) {
+ handler.handleException(e);
}
+ DSpaceCSV dSpaceCSV = metadataDSpaceCsvExportService
+ .handleExport(context, exportAllItems, exportAllMetadata, handle,
+ handler);
+ handler.writeFilestream(context, filename, dSpaceCSV.getInputStream(), EXPORT_CSV);
+ context.restoreAuthSystemState();
+ context.complete();
}
- /**
- * Build an array list of item ids that are in a community (include sub-communities and collections)
- *
- * @param context DSpace context
- * @param community The community to build from
- * @param indent How many spaces to use when writing out the names of items added
- * @return The list of item ids
- * @throws SQLException if database error
- */
- protected Iterator buildFromCommunity(Context context, Community community, int indent)
- throws SQLException {
- // Add all the collections
- List collections = community.getCollections();
- Iterator result = null;
- for (Collection collection : collections) {
- for (int i = 0; i < indent; i++) {
- System.out.print(" ");
- }
-
- Iterator items = itemService.findByCollection(context, collection);
- result = addItemsToResult(result, items);
-
- }
- // Add all the sub-communities
- List communities = community.getSubcommunities();
- for (Community subCommunity : communities) {
- for (int i = 0; i < indent; i++) {
- System.out.print(" ");
- }
- Iterator items = buildFromCommunity(context, subCommunity, indent + 1);
- result = addItemsToResult(result, items);
- }
-
- return result;
+ @Override
+ public MetadataExportScriptConfiguration getScriptConfiguration() {
+ return new DSpace().getServiceManager().getServiceByName("metadata-export",
+ MetadataExportScriptConfiguration.class);
}
- private Iterator addItemsToResult(Iterator result, Iterator items) {
- if (result == null) {
- result = items;
- } else {
- result = Iterators.concat(result, items);
- }
+ @Override
+ public void setup() throws ParseException {
- return result;
- }
-
- /**
- * Run the export
- *
- * @return the exported CSV lines
- */
- public DSpaceCSV export() {
- try {
- Context.Mode originalMode = context.getCurrentMode();
- context.setMode(Context.Mode.READ_ONLY);
-
- // Process each item
- DSpaceCSV csv = new DSpaceCSV(exportAll);
- while (toExport.hasNext()) {
- Item item = toExport.next();
- csv.addItem(item);
- context.uncacheEntity(item);
- }
-
- context.setMode(originalMode);
- // Return the results
- return csv;
- } catch (Exception e) {
- // Something went wrong...
- System.err.println("Error exporting to CSV:");
- e.printStackTrace();
- return null;
- }
- }
-
- /**
- * Print the help message
- *
- * @param options The command line options the user gave
- * @param exitCode the system exit code to use
- */
- private static void printHelp(Options options, int exitCode) {
- // print the help message
- HelpFormatter myhelp = new HelpFormatter();
- myhelp.printHelp("MetadataExport\n", options);
- System.out.println("\nfull export: metadataexport -f filename");
- System.out.println("partial export: metadataexport -i handle -f filename");
- System.exit(exitCode);
- }
-
- /**
- * main method to run the metadata exporter
- *
- * @param argv the command line arguments given
- * @throws Exception if error occurs
- */
- public static void main(String[] argv) throws Exception {
- // Create an options object and populate it
- CommandLineParser parser = new PosixParser();
-
- Options options = new Options();
-
- options.addOption("i", "id", true, "ID or handle of thing to export (item, collection, or community)");
- options.addOption("f", "file", true, "destination where you want file written");
- options.addOption("a", "all", false,
- "include all metadata fields that are not normally changed (e.g. provenance)");
- options.addOption("h", "help", false, "help");
-
- CommandLine line = null;
-
- try {
- line = parser.parse(options, argv);
- } catch (ParseException pe) {
- System.err.println("Error with commands.");
- printHelp(options, 1);
- System.exit(0);
- }
-
- if (line.hasOption('h')) {
- printHelp(options, 0);
+ if (commandLine.hasOption('h')) {
+ help = true;
+ return;
}
// Check a filename is given
- if (!line.hasOption('f')) {
- System.err.println("Required parameter -f missing!");
- printHelp(options, 1);
+ if (!commandLine.hasOption('f')) {
+ throw new ParseException("Required parameter -f missing!");
}
- String filename = line.getOptionValue('f');
+ filename = commandLine.getOptionValue('f');
- // Create a context
- Context c = new Context(Context.Mode.READ_ONLY);
- c.turnOffAuthorisationSystem();
+ exportAllMetadata = commandLine.hasOption('a');
- // The things we'll export
- Iterator toExport = null;
- MetadataExport exporter = null;
-
- // Export everything?
- boolean exportAll = line.hasOption('a');
-
- ContentServiceFactory contentServiceFactory = ContentServiceFactory.getInstance();
- // Check we have an item OK
- ItemService itemService = contentServiceFactory.getItemService();
- if (!line.hasOption('i')) {
- System.out.println("Exporting whole repository WARNING: May take some time!");
- exporter = new MetadataExport(c, itemService.findAll(c), exportAll);
- } else {
- String handle = line.getOptionValue('i');
- DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(c, handle);
- if (dso == null) {
- System.err.println("Item '" + handle + "' does not resolve to an item in your repository!");
- printHelp(options, 1);
- }
-
- if (dso.getType() == Constants.ITEM) {
- System.out.println("Exporting item '" + dso.getName() + "' (" + handle + ")");
- List item = new ArrayList<>();
- item.add((Item) dso);
- exporter = new MetadataExport(c, item.iterator(), exportAll);
- } else if (dso.getType() == Constants.COLLECTION) {
- System.out.println("Exporting collection '" + dso.getName() + "' (" + handle + ")");
- Collection collection = (Collection) dso;
- toExport = itemService.findByCollection(c, collection);
- exporter = new MetadataExport(c, toExport, exportAll);
- } else if (dso.getType() == Constants.COMMUNITY) {
- System.out.println("Exporting community '" + dso.getName() + "' (" + handle + ")");
- exporter = new MetadataExport(c, (Community) dso, exportAll);
- } else {
- System.err.println("Error identifying '" + handle + "'");
- System.exit(1);
- }
+ if (!commandLine.hasOption('i')) {
+ exportAllItems = true;
}
-
- // Perform the export
- DSpaceCSV csv = exporter.export();
-
- // Save the files to the file
- csv.save(filename);
-
- // Finish off and tidy up
- c.restoreAuthSystemState();
- c.complete();
+ handle = commandLine.getOptionValue('i');
}
}
diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExportScriptConfiguration.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExportScriptConfiguration.java
new file mode 100644
index 0000000000..65c0ddd8cf
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataExportScriptConfiguration.java
@@ -0,0 +1,74 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.bulkedit;
+
+import java.io.OutputStream;
+import java.sql.SQLException;
+
+import org.apache.commons.cli.Options;
+import org.dspace.authorize.service.AuthorizeService;
+import org.dspace.core.Context;
+import org.dspace.scripts.configuration.ScriptConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * The {@link ScriptConfiguration} for the {@link MetadataExport} script
+ */
+public class MetadataExportScriptConfiguration extends ScriptConfiguration {
+
+ @Autowired
+ private AuthorizeService authorizeService;
+
+ private Class dspaceRunnableClass;
+
+ @Override
+ public Class getDspaceRunnableClass() {
+ return dspaceRunnableClass;
+ }
+
+ /**
+ * Generic setter for the dspaceRunnableClass
+ * @param dspaceRunnableClass The dspaceRunnableClass to be set on this MetadataExportScriptConfiguration
+ */
+ @Override
+ public void setDspaceRunnableClass(Class dspaceRunnableClass) {
+ this.dspaceRunnableClass = dspaceRunnableClass;
+ }
+
+ @Override
+ public boolean isAllowedToExecute(Context context) {
+ try {
+ return authorizeService.isAdmin(context);
+ } catch (SQLException e) {
+ throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
+ }
+ }
+
+ @Override
+ public Options getOptions() {
+ if (options == null) {
+ Options options = new Options();
+
+ options.addOption("i", "id", true, "ID or handle of thing to export (item, collection, or community)");
+ options.getOption("i").setType(String.class);
+ options.addOption("f", "file", true, "destination where you want file written");
+ options.getOption("f").setType(OutputStream.class);
+ options.getOption("f").setRequired(true);
+ options.addOption("a", "all", false,
+ "include all metadata fields that are not normally changed (e.g. provenance)");
+ options.getOption("a").setType(boolean.class);
+ options.addOption("h", "help", false, "help");
+ options.getOption("h").setType(boolean.class);
+
+
+ super.options = options;
+ }
+ return options;
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java
index e8fff71cf4..eb0a4e2935 100644
--- a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java
+++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImport.java
@@ -7,10 +7,8 @@
*/
package org.dspace.app.bulkedit;
-import java.io.BufferedReader;
-import java.io.File;
import java.io.IOException;
-import java.io.InputStreamReader;
+import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
@@ -19,16 +17,12 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
-import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.authority.AuthorityValue;
@@ -65,6 +59,10 @@ import org.dspace.eperson.EPerson;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
+import org.dspace.scripts.DSpaceRunnable;
+import org.dspace.scripts.handler.DSpaceRunnableHandler;
+import org.dspace.utils.DSpace;
+import org.dspace.workflow.WorkflowException;
import org.dspace.workflow.WorkflowItem;
import org.dspace.workflow.WorkflowService;
import org.dspace.workflow.factory.WorkflowServiceFactory;
@@ -74,11 +72,7 @@ import org.dspace.workflow.factory.WorkflowServiceFactory;
*
* @author Stuart Lewis
*/
-public class MetadataImport {
- /**
- * The Context
- */
- Context c;
+public class MetadataImport extends DSpaceRunnable {
/**
* The DSpaceCSV object we're processing
@@ -95,10 +89,6 @@ public class MetadataImport {
*/
protected static Set authorityControlled;
- static {
- setAuthorizedMetadataFields();
- }
-
/**
* The prefix of the authority controlled field
*/
@@ -143,45 +133,208 @@ public class MetadataImport {
*/
protected Integer rowCount = 1;
+ private boolean useTemplate = false;
+ private String filename = null;
+ private boolean useWorkflow = false;
+ private boolean workflowNotify = false;
+ private boolean change = false;
+ private boolean help = false;
+ protected boolean validateOnly;
+
/**
* Logger
*/
protected static final Logger log = org.apache.logging.log4j.LogManager.getLogger(MetadataImport.class);
- protected final AuthorityValueService authorityValueService;
-
- protected final ItemService itemService;
- protected final InstallItemService installItemService;
- protected final CollectionService collectionService;
- protected final HandleService handleService;
- protected final WorkspaceItemService workspaceItemService;
- protected final RelationshipTypeService relationshipTypeService;
- protected final RelationshipService relationshipService;
- protected final EntityTypeService entityTypeService;
- protected final EntityService entityService;
+ protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
+ protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
+ protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
+ protected HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
+ protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
+ protected RelationshipTypeService relationshipTypeService = ContentServiceFactory.getInstance()
+ .getRelationshipTypeService();
+ protected RelationshipService relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
+ protected EntityTypeService entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
+ protected EntityService entityService = ContentServiceFactory.getInstance().getEntityService();
+ protected AuthorityValueService authorityValueService = AuthorityServiceFactory.getInstance()
+ .getAuthorityValueService();
/**
* Create an instance of the metadata importer. Requires a context and an array of CSV lines
* to examine.
*
- * @param c The context
* @param toImport An array of CSV lines to examine
*/
- public MetadataImport(Context c, DSpaceCSV toImport) {
+ public void initMetadataImport(DSpaceCSV toImport) {
// Store the import settings
- this.c = c;
- csv = toImport;
this.toImport = toImport.getCSVLines();
- installItemService = ContentServiceFactory.getInstance().getInstallItemService();
- itemService = ContentServiceFactory.getInstance().getItemService();
- collectionService = ContentServiceFactory.getInstance().getCollectionService();
- handleService = HandleServiceFactory.getInstance().getHandleService();
- authorityValueService = AuthorityServiceFactory.getInstance().getAuthorityValueService();
- workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
- relationshipService = ContentServiceFactory.getInstance().getRelationshipService();
- relationshipTypeService = ContentServiceFactory.getInstance().getRelationshipTypeService();
- entityTypeService = ContentServiceFactory.getInstance().getEntityTypeService();
- entityService = ContentServiceFactory.getInstance().getEntityService();
+ }
+
+ @Override
+ public void internalRun() throws Exception {
+ if (help) {
+ printHelp();
+ return;
+ }
+ // Create a context
+ Context c = null;
+ c = new Context();
+ c.turnOffAuthorisationSystem();
+
+ // Find the EPerson, assign to context
+ try {
+ if (commandLine.hasOption('e')) {
+ EPerson eperson;
+ String e = commandLine.getOptionValue('e');
+ if (e.indexOf('@') != -1) {
+ eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(c, e);
+ } else {
+ eperson = EPersonServiceFactory.getInstance().getEPersonService().find(c, UUID.fromString(e));
+ }
+
+ if (eperson == null) {
+ throw new ParseException("Error, eperson cannot be found: " + e);
+ }
+ c.setCurrentUser(eperson);
+ }
+ } catch (Exception e) {
+ throw new ParseException("Unable to find DSpace user: " + e.getMessage());
+ }
+
+ if (authorityControlled == null) {
+ setAuthorizedMetadataFields();
+ }
+ // Read commandLines from the CSV file
+ try {
+
+ Optional optionalFileStream = handler.getFileStream(c, filename);
+ if (optionalFileStream.isPresent()) {
+ csv = new DSpaceCSV(optionalFileStream.get(), c);
+ } else {
+ throw new IllegalArgumentException("Error reading file, the file couldn't be found for filename: " +
+ filename);
+ }
+ } catch (MetadataImportInvalidHeadingException miihe) {
+ throw miihe;
+ } catch (Exception e) {
+ throw new Exception("Error reading file: " + e.getMessage(), e);
+ }
+
+ // Perform the first import - just highlight differences
+ initMetadataImport(csv);
+ List changes;
+
+ if (!commandLine.hasOption('s') || validateOnly) {
+ // See what has changed
+ try {
+ changes = runImport(c, false, useWorkflow, workflowNotify, useTemplate);
+ } catch (MetadataImportException mie) {
+ throw mie;
+ }
+
+ // Display the changes
+ int changeCounter = displayChanges(changes, false);
+
+ // If there were changes, ask if we should execute them
+ if (!validateOnly && changeCounter > 0) {
+ try {
+ // Ask the user if they want to make the changes
+ handler.logInfo("\n" + changeCounter + " item(s) will be changed\n");
+ change = determineChange(handler);
+
+ } catch (IOException ioe) {
+ throw new IOException("Error: " + ioe.getMessage() + ", No changes have been made", ioe);
+ }
+ } else {
+ handler.logInfo("There were no changes detected");
+ }
+ } else {
+ change = true;
+ }
+
+ try {
+ // If required, make the change
+ if (change && !validateOnly) {
+ try {
+ // Make the changes
+ changes = runImport(c, true, useWorkflow, workflowNotify, useTemplate);
+ } catch (MetadataImportException mie) {
+ throw mie;
+ }
+
+ // Display the changes
+ displayChanges(changes, true);
+ }
+
+ // Finsh off and tidy up
+ c.restoreAuthSystemState();
+ c.complete();
+ } catch (Exception e) {
+ c.abort();
+ throw new Exception(
+ "Error committing changes to database: " + e.getMessage() + ", aborting most recent changes", e);
+ }
+
+ }
+
+ /**
+ * This method determines whether the changes should be applied or not. This is default set to true for the REST
+ * script as we don't want to interact with the caller. This will be overwritten in the CLI script to ask for
+ * confirmation
+ * @param handler Applicable DSpaceRunnableHandler
+ * @return boolean indicating the value
+ * @throws IOException If something goes wrong
+ */
+ protected boolean determineChange(DSpaceRunnableHandler handler) throws IOException {
+ return true;
+ }
+
+ @Override
+ public MetadataImportScriptConfiguration getScriptConfiguration() {
+ return new DSpace().getServiceManager().getServiceByName("metadata-import",
+ MetadataImportScriptConfiguration.class);
+ }
+
+
+ public void setup() throws ParseException {
+ useTemplate = false;
+ filename = null;
+ useWorkflow = false;
+ workflowNotify = false;
+
+ if (commandLine.hasOption('h')) {
+ help = true;
+ return;
+ }
+
+ // Check a filename is given
+ if (!commandLine.hasOption('f')) {
+ throw new ParseException("Required parameter -f missing!");
+ }
+ filename = commandLine.getOptionValue('f');
+ if (!commandLine.hasOption('e')) {
+ throw new ParseException("Required parameter -e missing!");
+ }
+
+ // Option to apply template to new items
+ if (commandLine.hasOption('t')) {
+ useTemplate = true;
+ }
+
+ // Options for workflows, and workflow notifications for new items
+ if (commandLine.hasOption('w')) {
+ useWorkflow = true;
+ if (commandLine.hasOption('n')) {
+ workflowNotify = true;
+ }
+ } else if (commandLine.hasOption('n')) {
+ throw new ParseException(
+ "Invalid option 'n': (notify) can only be specified with the 'w' (workflow) option.");
+ }
+ validateOnly = commandLine.hasOption('v');
+
+ // Is this a silent run?
+ change = false;
}
/**
@@ -195,281 +348,277 @@ public class MetadataImport {
* @return An array of BulkEditChange elements representing the items that have changed
* @throws MetadataImportException if something goes wrong
*/
- public List runImport(boolean change,
+ public List runImport(Context c, boolean change,
boolean useWorkflow,
boolean workflowNotify,
- boolean useTemplate) throws MetadataImportException {
+ boolean useTemplate)
+ throws MetadataImportException, SQLException, AuthorizeException, WorkflowException, IOException {
// Store the changes
ArrayList changes = new ArrayList();
// Make the changes
- try {
- Context.Mode originalMode = c.getCurrentMode();
- c.setMode(Context.Mode.BATCH_EDIT);
+ Context.Mode originalMode = c.getCurrentMode();
+ c.setMode(Context.Mode.BATCH_EDIT);
- // Process each change
- rowCount = 1;
- for (DSpaceCSVLine line : toImport) {
- // Resolve target references to other items
- populateRefAndRowMap(line, line.getID());
- line = resolveEntityRefs(line);
- // Get the DSpace item to compare with
- UUID id = line.getID();
+ // Process each change
+ rowCount = 1;
+ for (DSpaceCSVLine line : toImport) {
+ // Resolve target references to other items
+ populateRefAndRowMap(line, line.getID());
+ line = resolveEntityRefs(c, line);
+ // Get the DSpace item to compare with
+ UUID id = line.getID();
- // Is there an action column?
- if (csv.hasActions() && (!"".equals(line.getAction())) && (id == null)) {
- throw new MetadataImportException("'action' not allowed for new items!");
- }
-
- WorkspaceItem wsItem = null;
- WorkflowItem wfItem = null;
- Item item = null;
-
- // Is this an existing item?
- if (id != null) {
- // Get the item
- item = itemService.find(c, id);
- if (item == null) {
- throw new MetadataImportException("Unknown item ID " + id);
- }
-
- // Record changes
- BulkEditChange whatHasChanged = new BulkEditChange(item);
-
- // Has it moved collection?
- List collections = line.get("collection");
- if (collections != null) {
- // Sanity check we're not orphaning it
- if (collections.size() == 0) {
- throw new MetadataImportException("Missing collection from item " + item.getHandle());
- }
- List actualCollections = item.getCollections();
- compare(item, collections, actualCollections, whatHasChanged, change);
- }
-
- // Iterate through each metadata element in the csv line
- for (String md : line.keys()) {
- // Get the values we already have
- if (!"id".equals(md)) {
- // Get the values from the CSV
- String[] fromCSV = line.get(md).toArray(new String[line.get(md).size()]);
- // Remove authority unless the md is not authority controlled
- if (!isAuthorityControlledField(md)) {
- for (int i = 0; i < fromCSV.length; i++) {
- int pos = fromCSV[i].indexOf(csv.getAuthoritySeparator());
- if (pos > -1) {
- fromCSV[i] = fromCSV[i].substring(0, pos);
- }
- }
- }
- // Compare
- compareAndUpdate(item, fromCSV, change, md, whatHasChanged, line);
- }
- }
-
- if (csv.hasActions()) {
- // Perform the action
- String action = line.getAction();
- if ("".equals(action)) {
- // Do nothing
- } else if ("expunge".equals(action)) {
- // Does the configuration allow deletes?
- if (!ConfigurationManager.getBooleanProperty("bulkedit", "allowexpunge", false)) {
- throw new MetadataImportException("'expunge' action denied by configuration");
- }
-
- // Remove the item
-
- if (change) {
- itemService.delete(c, item);
- }
-
- whatHasChanged.setDeleted();
- } else if ("withdraw".equals(action)) {
- // Withdraw the item
- if (!item.isWithdrawn()) {
- if (change) {
- itemService.withdraw(c, item);
- }
- whatHasChanged.setWithdrawn();
- }
- } else if ("reinstate".equals(action)) {
- // Reinstate the item
- if (item.isWithdrawn()) {
- if (change) {
- itemService.reinstate(c, item);
- }
- whatHasChanged.setReinstated();
- }
- } else {
- // Unknown action!
- throw new MetadataImportException("Unknown action: " + action);
- }
- }
-
- // Only record if changes have been made
- if (whatHasChanged.hasChanges()) {
- changes.add(whatHasChanged);
- }
- } else {
- // This is marked as a new item, so no need to compare
-
- // First check a user is set, otherwise this can't happen
- if (c.getCurrentUser() == null) {
- throw new MetadataImportException(
- "When adding new items, a user must be specified with the -e option");
- }
-
- // Iterate through each metadata element in the csv line
- BulkEditChange whatHasChanged = new BulkEditChange();
- for (String md : line.keys()) {
- // Get the values we already have
- if (!"id".equals(md) && !"rowName".equals(md)) {
- // Get the values from the CSV
- String[] fromCSV = line.get(md).toArray(new String[line.get(md).size()]);
-
- // Remove authority unless the md is not authority controlled
- if (!isAuthorityControlledField(md)) {
- for (int i = 0; i < fromCSV.length; i++) {
- int pos = fromCSV[i].indexOf(csv.getAuthoritySeparator());
- if (pos > -1) {
- fromCSV[i] = fromCSV[i].substring(0, pos);
- }
- }
- }
-
- // Add all the values from the CSV line
- add(fromCSV, md, whatHasChanged);
- }
- }
-
- // Check it has an owning collection
- List collections = line.get("collection");
- if (collections == null) {
- throw new MetadataImportException(
- "New items must have a 'collection' assigned in the form of a handle");
- }
-
- // Check collections are really collections
- ArrayList check = new ArrayList();
- Collection collection;
- for (String handle : collections) {
- try {
- // Resolve the handle to the collection
- collection = (Collection) handleService.resolveToObject(c, handle);
-
- // Check it resolved OK
- if (collection == null) {
- throw new MetadataImportException(
- "'" + handle + "' is not a Collection! You must specify a valid collection for " +
- "new items");
- }
-
- // Check for duplicate
- if (check.contains(collection)) {
- throw new MetadataImportException(
- "Duplicate collection assignment detected in new item! " + handle);
- } else {
- check.add(collection);
- }
- } catch (Exception ex) {
- throw new MetadataImportException(
- "'" + handle + "' is not a Collection! You must specify a valid collection for new " +
- "items",
- ex);
- }
- }
-
- // Record the addition to collections
- boolean first = true;
- for (String handle : collections) {
- Collection extra = (Collection) handleService.resolveToObject(c, handle);
- if (first) {
- whatHasChanged.setOwningCollection(extra);
- } else {
- whatHasChanged.registerNewMappedCollection(extra);
- }
- first = false;
- }
-
- // Create the new item?
- if (change) {
- // Create the item
- String collectionHandle = line.get("collection").get(0);
- collection = (Collection) handleService.resolveToObject(c, collectionHandle);
- wsItem = workspaceItemService.create(c, collection, useTemplate);
- item = wsItem.getItem();
-
- // Add the metadata to the item
- for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) {
- if (!StringUtils.equals(dcv.getSchema(), MetadataSchemaEnum.RELATION.getName())) {
- itemService.addMetadata(c, item, dcv.getSchema(),
- dcv.getElement(),
- dcv.getQualifier(),
- dcv.getLanguage(),
- dcv.getValue(),
- dcv.getAuthority(),
- dcv.getConfidence());
- }
- }
- //Add relations after all metadata has been processed
- for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) {
- if (StringUtils.equals(dcv.getSchema(), MetadataSchemaEnum.RELATION.getName())) {
- addRelationship(c, item, dcv.getElement(), dcv.getValue());
- }
- }
-
-
- // Should the workflow be used?
- if (useWorkflow) {
- WorkflowService workflowService = WorkflowServiceFactory.getInstance().getWorkflowService();
- if (workflowNotify) {
- wfItem = workflowService.start(c, wsItem);
- } else {
- wfItem = workflowService.startWithoutNotify(c, wsItem);
- }
- } else {
- // Install the item
- installItemService.installItem(c, wsItem);
- }
-
- // Add to extra collections
- if (line.get("collection").size() > 0) {
- for (int i = 1; i < collections.size(); i++) {
- String handle = collections.get(i);
- Collection extra = (Collection) handleService.resolveToObject(c, handle);
- collectionService.addItem(c, extra, item);
- }
- }
-
- whatHasChanged.setItem(item);
- }
-
- // Record the changes
- changes.add(whatHasChanged);
- }
-
- if (change) {
- //only clear cache if changes have been made.
- c.uncacheEntity(wsItem);
- c.uncacheEntity(wfItem);
- c.uncacheEntity(item);
- }
- populateRefAndRowMap(line, item == null ? null : item.getID());
- // keep track of current rows processed
- rowCount++;
+ // Is there an action column?
+ if (csv.hasActions() && (!"".equals(line.getAction())) && (id == null)) {
+ throw new MetadataImportException("'action' not allowed for new items!");
}
- c.setMode(originalMode);
- } catch (MetadataImportException mie) {
- throw mie;
- } catch (Exception e) {
- e.printStackTrace();
+ WorkspaceItem wsItem = null;
+ WorkflowItem wfItem = null;
+ Item item = null;
+
+ // Is this an existing item?
+ if (id != null) {
+ // Get the item
+ item = itemService.find(c, id);
+ if (item == null) {
+ throw new MetadataImportException("Unknown item ID " + id);
+ }
+
+ // Record changes
+ BulkEditChange whatHasChanged = new BulkEditChange(item);
+
+ // Has it moved collection?
+ List collections = line.get("collection");
+ if (collections != null) {
+ // Sanity check we're not orphaning it
+ if (collections.size() == 0) {
+ throw new MetadataImportException("Missing collection from item " + item.getHandle());
+ }
+ List actualCollections = item.getCollections();
+ compare(c, item, collections, actualCollections, whatHasChanged, change);
+ }
+
+ // Iterate through each metadata element in the csv line
+ for (String md : line.keys()) {
+ // Get the values we already have
+ if (!"id".equals(md)) {
+ // Get the values from the CSV
+ String[] fromCSV = line.get(md).toArray(new String[line.get(md).size()]);
+ // Remove authority unless the md is not authority controlled
+ if (!isAuthorityControlledField(md)) {
+ for (int i = 0; i < fromCSV.length; i++) {
+ int pos = fromCSV[i].indexOf(csv.getAuthoritySeparator());
+ if (pos > -1) {
+ fromCSV[i] = fromCSV[i].substring(0, pos);
+ }
+ }
+ }
+ // Compare
+ compareAndUpdate(c, item, fromCSV, change, md, whatHasChanged, line);
+ }
+ }
+
+ if (csv.hasActions()) {
+ // Perform the action
+ String action = line.getAction();
+ if ("".equals(action)) {
+ // Do nothing
+ } else if ("expunge".equals(action)) {
+ // Does the configuration allow deletes?
+ if (!ConfigurationManager.getBooleanProperty("bulkedit", "allowexpunge", false)) {
+ throw new MetadataImportException("'expunge' action denied by configuration");
+ }
+
+ // Remove the item
+
+ if (change) {
+ itemService.delete(c, item);
+ }
+
+ whatHasChanged.setDeleted();
+ } else if ("withdraw".equals(action)) {
+ // Withdraw the item
+ if (!item.isWithdrawn()) {
+ if (change) {
+ itemService.withdraw(c, item);
+ }
+ whatHasChanged.setWithdrawn();
+ }
+ } else if ("reinstate".equals(action)) {
+ // Reinstate the item
+ if (item.isWithdrawn()) {
+ if (change) {
+ itemService.reinstate(c, item);
+ }
+ whatHasChanged.setReinstated();
+ }
+ } else {
+ // Unknown action!
+ throw new MetadataImportException("Unknown action: " + action);
+ }
+ }
+
+ // Only record if changes have been made
+ if (whatHasChanged.hasChanges()) {
+ changes.add(whatHasChanged);
+ }
+ } else {
+ // This is marked as a new item, so no need to compare
+
+ // First check a user is set, otherwise this can't happen
+ if (c.getCurrentUser() == null) {
+ throw new MetadataImportException(
+ "When adding new items, a user must be specified with the -e option");
+ }
+
+ // Iterate through each metadata element in the csv line
+ BulkEditChange whatHasChanged = new BulkEditChange();
+ for (String md : line.keys()) {
+ // Get the values we already have
+ if (!"id".equals(md) && !"rowName".equals(md)) {
+ // Get the values from the CSV
+ String[] fromCSV = line.get(md).toArray(new String[line.get(md).size()]);
+
+ // Remove authority unless the md is not authority controlled
+ if (!isAuthorityControlledField(md)) {
+ for (int i = 0; i < fromCSV.length; i++) {
+ int pos = fromCSV[i].indexOf(csv.getAuthoritySeparator());
+ if (pos > -1) {
+ fromCSV[i] = fromCSV[i].substring(0, pos);
+ }
+ }
+ }
+
+ // Add all the values from the CSV line
+ add(c, fromCSV, md, whatHasChanged);
+ }
+ }
+
+ // Check it has an owning collection
+ List collections = line.get("collection");
+ if (collections == null) {
+ throw new MetadataImportException(
+ "New items must have a 'collection' assigned in the form of a handle");
+ }
+
+ // Check collections are really collections
+ ArrayList check = new ArrayList();
+ Collection collection;
+ for (String handle : collections) {
+ try {
+ // Resolve the handle to the collection
+ collection = (Collection) handleService.resolveToObject(c, handle);
+
+ // Check it resolved OK
+ if (collection == null) {
+ throw new MetadataImportException(
+ "'" + handle + "' is not a Collection! You must specify a valid collection for " +
+ "new items");
+ }
+
+ // Check for duplicate
+ if (check.contains(collection)) {
+ throw new MetadataImportException(
+ "Duplicate collection assignment detected in new item! " + handle);
+ } else {
+ check.add(collection);
+ }
+ } catch (Exception ex) {
+ throw new MetadataImportException(
+ "'" + handle + "' is not a Collection! You must specify a valid collection for new " +
+ "items",
+ ex);
+ }
+ }
+
+ // Record the addition to collections
+ boolean first = true;
+ for (String handle : collections) {
+ Collection extra = (Collection) handleService.resolveToObject(c, handle);
+ if (first) {
+ whatHasChanged.setOwningCollection(extra);
+ } else {
+ whatHasChanged.registerNewMappedCollection(extra);
+ }
+ first = false;
+ }
+
+ // Create the new item?
+ if (change) {
+ // Create the item
+ String collectionHandle = line.get("collection").get(0);
+ collection = (Collection) handleService.resolveToObject(c, collectionHandle);
+ wsItem = workspaceItemService.create(c, collection, useTemplate);
+ item = wsItem.getItem();
+
+ // Add the metadata to the item
+ for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) {
+ if (!StringUtils.equals(dcv.getSchema(), MetadataSchemaEnum.RELATION.getName())) {
+ itemService.addMetadata(c, item, dcv.getSchema(),
+ dcv.getElement(),
+ dcv.getQualifier(),
+ dcv.getLanguage(),
+ dcv.getValue(),
+ dcv.getAuthority(),
+ dcv.getConfidence());
+ }
+ }
+ //Add relations after all metadata has been processed
+ for (BulkEditMetadataValue dcv : whatHasChanged.getAdds()) {
+ if (StringUtils.equals(dcv.getSchema(), MetadataSchemaEnum.RELATION.getName())) {
+ addRelationship(c, item, dcv.getElement(), dcv.getValue());
+ }
+ }
+
+
+ // Should the workflow be used?
+ if (useWorkflow) {
+ WorkflowService workflowService = WorkflowServiceFactory.getInstance().getWorkflowService();
+ if (workflowNotify) {
+ wfItem = workflowService.start(c, wsItem);
+ } else {
+ wfItem = workflowService.startWithoutNotify(c, wsItem);
+ }
+ } else {
+ // Install the item
+ installItemService.installItem(c, wsItem);
+ }
+
+ // Add to extra collections
+ if (line.get("collection").size() > 0) {
+ for (int i = 1; i < collections.size(); i++) {
+ String handle = collections.get(i);
+ Collection extra = (Collection) handleService.resolveToObject(c, handle);
+ collectionService.addItem(c, extra, item);
+ }
+ }
+
+ whatHasChanged.setItem(item);
+ }
+
+ // Record the changes
+ changes.add(whatHasChanged);
+ }
+
+ if (change) {
+ //only clear cache if changes have been made.
+ c.uncacheEntity(wsItem);
+ c.uncacheEntity(wfItem);
+ c.uncacheEntity(item);
+ }
+ populateRefAndRowMap(line, item == null ? null : item.getID());
+ // keep track of current rows processed
+ rowCount++;
}
+ c.setMode(originalMode);
+
+
// Return the changes
- if (!change ) {
- validateExpressedRelations();
+ if (!change) {
+ validateExpressedRelations(c);
}
return changes;
}
@@ -487,7 +636,7 @@ public class MetadataImport {
* @throws AuthorizeException if there is an authorization problem with permissions
* @throws MetadataImportException custom exception for error handling within metadataimport
*/
- protected void compareAndUpdate(Item item, String[] fromCSV, boolean change,
+ protected void compareAndUpdate(Context c, Item item, String[] fromCSV, boolean change,
String md, BulkEditChange changes, DSpaceCSVLine line)
throws SQLException, AuthorizeException, MetadataImportException {
// Log what metadata element we're looking at
@@ -565,7 +714,7 @@ public class MetadataImport {
// Compare from current->csv
for (int v = 0; v < fromCSV.length; v++) {
String value = fromCSV[v];
- BulkEditMetadataValue dcv = getBulkEditValueFromCSV(language, schema, element, qualifier, value,
+ BulkEditMetadataValue dcv = getBulkEditValueFromCSV(c, language, schema, element, qualifier, value,
fromAuthority);
if (fromAuthority != null) {
value = dcv.getValue() + csv.getAuthoritySeparator() + dcv.getAuthority() + csv
@@ -694,8 +843,8 @@ public class MetadataImport {
* @throws AuthorizeException If something goes wrong
*/
private void addRelationships(Context c, Item item, String typeName, List values)
- throws SQLException, AuthorizeException,
- MetadataImportException {
+ throws SQLException, AuthorizeException,
+ MetadataImportException {
for (String value : values) {
addRelationship(c, item, typeName, value);
}
@@ -746,22 +895,23 @@ public class MetadataImport {
Entity relationEntity = getEntity(c, value);
// Get relationship type of entity and item
String relationEntityRelationshipType = itemService.getMetadata(relationEntity.getItem(),
- "relationship", "type",
- null, Item.ANY).get(0).getValue();
+ "relationship", "type",
+ null, Item.ANY).get(0).getValue();
String itemRelationshipType = itemService.getMetadata(item, "relationship", "type",
- null, Item.ANY).get(0).getValue();
+ null, Item.ANY).get(0).getValue();
// Get the correct RelationshipType based on typeName
List relType = relationshipTypeService.findByLeftwardOrRightwardTypeName(c, typeName);
RelationshipType foundRelationshipType = matchRelationshipType(relType,
- relationEntityRelationshipType, itemRelationshipType, typeName);
+ relationEntityRelationshipType,
+ itemRelationshipType, typeName);
if (foundRelationshipType == null) {
throw new MetadataImportException("Error on CSV row " + rowCount + ":" + "\n" +
- "No Relationship type found for:\n" +
- "Target type: " + relationEntityRelationshipType + "\n" +
- "Origin referer type: " + itemRelationshipType + "\n" +
- "with typeName: " + typeName);
+ "No Relationship type found for:\n" +
+ "Target type: " + relationEntityRelationshipType + "\n" +
+ "Origin referer type: " + itemRelationshipType + "\n" +
+ "with typeName: " + typeName);
}
if (foundRelationshipType.getLeftwardType().equalsIgnoreCase(typeName)) {
@@ -783,7 +933,7 @@ public class MetadataImport {
int leftPlace = relationshipService.findNextLeftPlaceByLeftItem(c, leftItem);
int rightPlace = relationshipService.findNextRightPlaceByRightItem(c, rightItem);
Relationship persistedRelationship = relationshipService.create(c, leftItem, rightItem,
- foundRelationshipType, leftPlace, rightPlace);
+ foundRelationshipType, leftPlace, rightPlace);
relationshipService.update(c, persistedRelationship);
}
@@ -801,7 +951,7 @@ public class MetadataImport {
* @throws IOException Can be thrown when moving items in communities
* @throws MetadataImportException If something goes wrong to be reported back to the user
*/
- protected void compare(Item item,
+ protected void compare(Context c, Item item,
List collections,
List actualCollections,
BulkEditChange bechange,
@@ -898,8 +1048,8 @@ public class MetadataImport {
// Remove from old owned collection (if still a member)
if (bechange.getOldOwningCollection() != null) {
boolean found = false;
- for (Collection c : item.getCollections()) {
- if (c.getID().equals(bechange.getOldOwningCollection().getID())) {
+ for (Collection collection : item.getCollections()) {
+ if (collection.getID().equals(bechange.getOldOwningCollection().getID())) {
found = true;
}
}
@@ -926,7 +1076,7 @@ public class MetadataImport {
* @throws SQLException when an SQL error has occurred (querying DSpace)
* @throws AuthorizeException If the user can't make the changes
*/
- protected void add(String[] fromCSV, String md, BulkEditChange changes)
+ protected void add(Context c, String[] fromCSV, String md, BulkEditChange changes)
throws SQLException, AuthorizeException {
// Don't add owning collection or action
if (("collection".equals(md)) || ("action".equals(md))) {
@@ -964,7 +1114,7 @@ public class MetadataImport {
// Add all the values
for (String value : fromCSV) {
- BulkEditMetadataValue dcv = getBulkEditValueFromCSV(language, schema, element, qualifier, value,
+ BulkEditMetadataValue dcv = getBulkEditValueFromCSV(c, language, schema, element, qualifier, value,
fromAuthority);
if (fromAuthority != null) {
value = dcv.getValue() + csv.getAuthoritySeparator() + dcv.getAuthority() + csv
@@ -978,7 +1128,7 @@ public class MetadataImport {
}
}
- protected BulkEditMetadataValue getBulkEditValueFromCSV(String language, String schema, String element,
+ protected BulkEditMetadataValue getBulkEditValueFromCSV(Context c, String language, String schema, String element,
String qualifier, String value,
AuthorityValue fromAuthority) {
// Look to see if it should be removed
@@ -1057,20 +1207,6 @@ public class MetadataImport {
return in.replaceAll("\r\n", "").replaceAll("\n", "").trim();
}
- /**
- * Print the help message
- *
- * @param options The command line options the user gave
- * @param exitCode the system exit code to use
- */
- private static void printHelp(Options options, int exitCode) {
- // print the help message
- HelpFormatter myhelp = new HelpFormatter();
- myhelp.printHelp("MetatadataImport\n", options);
- System.out.println("\nmetadataimport: MetadataImport -f filename");
- System.exit(exitCode);
- }
-
/**
* Display the changes that have been detected, or that have been made
*
@@ -1078,7 +1214,7 @@ public class MetadataImport {
* @param changed Whether or not the changes have been made
* @return The number of items that have changed
*/
- private static int displayChanges(List changes, boolean changed) {
+ private int displayChanges(List changes, boolean changed) {
// Display the changes
int changeCounter = 0;
for (BulkEditChange change : changes) {
@@ -1093,20 +1229,18 @@ public class MetadataImport {
(change.isDeleted()) || (change.isWithdrawn()) || (change.isReinstated())) {
// Show the item
Item i = change.getItem();
-
- System.out.println("-----------------------------------------------------------");
+ handler.logInfo("-----------------------------------------------------------");
if (!change.isNewItem()) {
- System.out.println("Changes for item: " + i.getID() + " (" + i.getHandle() + ")");
+ handler.logInfo("Changes for item: " + i.getID() + " (" + i.getHandle() + ")");
} else {
- System.out.print("New item: ");
+ handler.logInfo("New item: ");
if (i != null) {
if (i.getHandle() != null) {
- System.out.print(i.getID() + " (" + i.getHandle() + ")");
+ handler.logInfo(i.getID() + " (" + i.getHandle() + ")");
} else {
- System.out.print(i.getID() + " (in workflow)");
+ handler.logInfo(i.getID() + " (in workflow)");
}
}
- System.out.println();
}
changeCounter++;
}
@@ -1114,23 +1248,23 @@ public class MetadataImport {
// Show actions
if (change.isDeleted()) {
if (changed) {
- System.out.println(" - EXPUNGED!");
+ handler.logInfo(" - EXPUNGED!");
} else {
- System.out.println(" - EXPUNGE!");
+ handler.logInfo(" - EXPUNGE!");
}
}
if (change.isWithdrawn()) {
if (changed) {
- System.out.println(" - WITHDRAWN!");
+ handler.logInfo(" - WITHDRAWN!");
} else {
- System.out.println(" - WITHDRAW!");
+ handler.logInfo(" - WITHDRAW!");
}
}
if (change.isReinstated()) {
if (changed) {
- System.out.println(" - REINSTATED!");
+ handler.logInfo(" - REINSTATED!");
} else {
- System.out.println(" - REINSTATE!");
+ handler.logInfo(" - REINSTATE!");
}
}
@@ -1140,11 +1274,11 @@ public class MetadataImport {
String cHandle = c.getHandle();
String cName = c.getName();
if (!changed) {
- System.out.print(" + New owning collection (" + cHandle + "): ");
+ handler.logInfo(" + New owning collection (" + cHandle + "): ");
} else {
- System.out.print(" + New owning collection (" + cHandle + "): ");
+ handler.logInfo(" + New owning collection (" + cHandle + "): ");
}
- System.out.println(cName);
+ handler.logInfo(cName);
}
c = change.getOldOwningCollection();
@@ -1152,11 +1286,11 @@ public class MetadataImport {
String cHandle = c.getHandle();
String cName = c.getName();
if (!changed) {
- System.out.print(" + Old owning collection (" + cHandle + "): ");
+ handler.logInfo(" + Old owning collection (" + cHandle + "): ");
} else {
- System.out.print(" + Old owning collection (" + cHandle + "): ");
+ handler.logInfo(" + Old owning collection (" + cHandle + "): ");
}
- System.out.println(cName);
+ handler.logInfo(cName);
}
}
@@ -1165,11 +1299,11 @@ public class MetadataImport {
String cHandle = c.getHandle();
String cName = c.getName();
if (!changed) {
- System.out.print(" + Map to collection (" + cHandle + "): ");
+ handler.logInfo(" + Map to collection (" + cHandle + "): ");
} else {
- System.out.print(" + Mapped to collection (" + cHandle + "): ");
+ handler.logInfo(" + Mapped to collection (" + cHandle + "): ");
}
- System.out.println(cName);
+ handler.logInfo(cName);
}
// Show old mapped collections
@@ -1177,11 +1311,11 @@ public class MetadataImport {
String cHandle = c.getHandle();
String cName = c.getName();
if (!changed) {
- System.out.print(" + Un-map from collection (" + cHandle + "): ");
+ handler.logInfo(" + Un-map from collection (" + cHandle + "): ");
} else {
- System.out.print(" + Un-mapped from collection (" + cHandle + "): ");
+ handler.logInfo(" + Un-mapped from collection (" + cHandle + "): ");
}
- System.out.println(cName);
+ handler.logInfo(cName);
}
// Show additions
@@ -1194,16 +1328,15 @@ public class MetadataImport {
md += "[" + metadataValue.getLanguage() + "]";
}
if (!changed) {
- System.out.print(" + Add (" + md + "): ");
+ handler.logInfo(" + Add (" + md + "): ");
} else {
- System.out.print(" + Added (" + md + "): ");
+ handler.logInfo(" + Added (" + md + "): ");
}
- System.out.print(metadataValue.getValue());
+ handler.logInfo(metadataValue.getValue());
if (isAuthorityControlledField(md)) {
- System.out.print(", authority = " + metadataValue.getAuthority());
- System.out.print(", confidence = " + metadataValue.getConfidence());
+ handler.logInfo(", authority = " + metadataValue.getAuthority());
+ handler.logInfo(", confidence = " + metadataValue.getConfidence());
}
- System.out.println("");
}
// Show removals
@@ -1216,16 +1349,15 @@ public class MetadataImport {
md += "[" + metadataValue.getLanguage() + "]";
}
if (!changed) {
- System.out.print(" - Remove (" + md + "): ");
+ handler.logInfo(" - Remove (" + md + "): ");
} else {
- System.out.print(" - Removed (" + md + "): ");
+ handler.logInfo(" - Removed (" + md + "): ");
}
- System.out.print(metadataValue.getValue());
+ handler.logInfo(metadataValue.getValue());
if (isAuthorityControlledField(md)) {
- System.out.print(", authority = " + metadataValue.getAuthority());
- System.out.print(", confidence = " + metadataValue.getConfidence());
+ handler.logInfo(", authority = " + metadataValue.getAuthority());
+ handler.logInfo(", confidence = " + metadataValue.getConfidence());
}
- System.out.println("");
}
}
return changeCounter;
@@ -1243,7 +1375,7 @@ public class MetadataImport {
/**
* Set authority controlled fields
*/
- private static void setAuthorizedMetadataFields() {
+ private void setAuthorizedMetadataFields() {
authorityControlled = new HashSet();
Enumeration propertyNames = ConfigurationManager.getProperties().propertyNames();
while (propertyNames.hasMoreElements()) {
@@ -1255,191 +1387,6 @@ public class MetadataImport {
}
}
- /**
- * main method to run the metadata exporter
- *
- * @param argv the command line arguments given
- */
- public static void main(String[] argv) {
- // Create an options object and populate it
- CommandLineParser parser = new PosixParser();
-
- Options options = new Options();
-
- options.addOption("f", "file", true, "source file");
- options.addOption("e", "email", true, "email address or user id of user (required if adding new items)");
- options.addOption("s", "silent", false,
- "silent operation - doesn't request confirmation of changes USE WITH CAUTION");
- options.addOption("w", "workflow", false, "workflow - when adding new items, use collection workflow");
- options.addOption("n", "notify", false,
- "notify - when adding new items using a workflow, send notification emails");
- options.addOption("t", "template", false,
- "template - when adding new items, use the collection template (if it exists)");
- options.addOption("v", "validate-only", false,
- "validate - just validate the csv, don't run the import");
- options.addOption("h", "help", false, "help");
-
- // Parse the command line arguments
- CommandLine line;
- try {
- line = parser.parse(options, argv);
- } catch (ParseException pe) {
- System.err.println("Error parsing command line arguments: " + pe.getMessage());
- System.exit(1);
- return;
- }
-
- if (line.hasOption('h')) {
- printHelp(options, 0);
- }
-
- // Check a filename is given
- if (!line.hasOption('f')) {
- System.err.println("Required parameter -f missing!");
- printHelp(options, 1);
- }
- String filename = line.getOptionValue('f');
-
- // Option to apply template to new items
- boolean useTemplate = false;
- if (line.hasOption('t')) {
- useTemplate = true;
- }
-
- // Options for workflows, and workflow notifications for new items
- boolean useWorkflow = false;
- boolean workflowNotify = false;
- if (line.hasOption('w')) {
- useWorkflow = true;
- if (line.hasOption('n')) {
- workflowNotify = true;
- }
- } else if (line.hasOption('n')) {
- System.err.println("Invalid option 'n': (notify) can only be specified with the 'w' (workflow) option.");
- System.exit(1);
- }
-
- // Create a context
- Context c;
- try {
- c = new Context();
- c.turnOffAuthorisationSystem();
- } catch (Exception e) {
- System.err.println("Unable to create a new DSpace Context: " + e.getMessage());
- System.exit(1);
- return;
- }
-
- // Find the EPerson, assign to context
- try {
- if (line.hasOption('e')) {
- EPerson eperson;
- String e = line.getOptionValue('e');
- if (e.indexOf('@') != -1) {
- eperson = EPersonServiceFactory.getInstance().getEPersonService().findByEmail(c, e);
- } else {
- eperson = EPersonServiceFactory.getInstance().getEPersonService().find(c, UUID.fromString(e));
- }
-
- if (eperson == null) {
- System.out.println("Error, eperson cannot be found: " + e);
- System.exit(1);
- }
- c.setCurrentUser(eperson);
- }
- } catch (Exception e) {
- System.err.println("Unable to find DSpace user: " + e.getMessage());
- System.exit(1);
- return;
- }
-
- // Is this a silent run?
- boolean change = false;
-
- // Read lines from the CSV file
- DSpaceCSV csv;
- try {
- csv = new DSpaceCSV(new File(filename), c);
- } catch (MetadataImportInvalidHeadingException miihe) {
- System.err.println(miihe.getMessage());
- System.exit(1);
- return;
- } catch (Exception e) {
- System.err.println("Error reading file: " + e.getMessage());
- System.exit(1);
- return;
- }
-
- // Perform the first import - just highlight differences
- MetadataImport importer = new MetadataImport(c, csv);
- List changes;
-
- boolean validateOnly = line.hasOption('v');
-
- if (!line.hasOption('s') || validateOnly) {
- // See what has changed
- try {
- changes = importer.runImport(false, useWorkflow, workflowNotify, useTemplate);
- } catch (MetadataImportException mie) {
- System.err.println("Error: " + mie.getMessage());
- System.exit(1);
- return;
- }
-
- // Display the changes
- int changeCounter = displayChanges(changes, false);
-
- // If there were changes, ask if we should execute them
- if (!validateOnly && changeCounter > 0) {
- try {
- // Ask the user if they want to make the changes
- System.out.println("\n" + changeCounter + " item(s) will be changed\n");
- System.out.print("Do you want to make these changes? [y/n] ");
- String yn = (new BufferedReader(new InputStreamReader(System.in))).readLine();
- if ("y".equalsIgnoreCase(yn)) {
- change = true;
- } else {
- System.out.println("No data has been changed.");
- }
- } catch (IOException ioe) {
- System.err.println("Error: " + ioe.getMessage());
- System.err.println("No changes have been made");
- System.exit(1);
- }
- } else {
- System.out.println("There were no changes detected");
- }
- } else {
- change = true;
- }
-
- try {
- // If required, make the change
- if (change && !validateOnly) {
- try {
- // Make the changes
- changes = importer.runImport(true, useWorkflow, workflowNotify, useTemplate);
- } catch (MetadataImportException mie) {
- System.err.println("Error: " + mie.getMessage());
- System.exit(1);
- return;
- }
-
- // Display the changes
- displayChanges(changes, true);
- }
-
- // Finsh off and tidy up
- c.restoreAuthSystemState();
- c.complete();
- } catch (Exception e) {
- c.abort();
- System.err.println("Error committing changes to database: " + e.getMessage());
- System.err.println("Aborting most recent changes.");
- System.exit(1);
- }
- }
-
/**
* Gets a copy of the given csv line with all entity target references resolved to UUID strings.
* Keys being iterated over represent metadatafields or special columns to be processed.
@@ -1448,7 +1395,7 @@ public class MetadataImport {
* @return a copy, with all references resolved.
* @throws MetadataImportException if there is an error resolving any entity target reference.
*/
- public DSpaceCSVLine resolveEntityRefs(DSpaceCSVLine line) throws MetadataImportException {
+ public DSpaceCSVLine resolveEntityRefs(Context c, DSpaceCSVLine line) throws MetadataImportException {
DSpaceCSVLine newLine = new DSpaceCSVLine(line.getID());
UUID originId = evaluateOriginId(line.getID());
for (String key : line.keys()) {
@@ -1503,7 +1450,7 @@ public class MetadataImport {
originIds.add(originId);
typeNames.put(relationField, originIds);
} else {
- ArrayList originIds = typeNames.get(relationField);
+ ArrayList originIds = typeNames.get(relationField);
originIds.add(originId);
typeNames.put(relationField, originIds);
}
@@ -1533,7 +1480,7 @@ public class MetadataImport {
}
for (String key : line.keys()) {
if (key.contains(".") && !key.split("\\.")[0].equalsIgnoreCase("relation") ||
- key.equalsIgnoreCase("rowName")) {
+ key.equalsIgnoreCase("rowName")) {
for (String value : line.get(key)) {
String valueKey = key + ":" + value;
Set rowNums = csvRefMap.get(valueKey);
@@ -1575,20 +1522,20 @@ public class MetadataImport {
try {
return UUID.fromString(reference);
} catch (IllegalArgumentException e) {
- throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
- "Not a UUID or indirect entity reference: '" + reference + "'");
+ throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
+ "Not a UUID or indirect entity reference: '" + reference + "'");
}
- } else if (!reference.startsWith("rowName:") ) { // Not a rowName ref; so it's a metadata value reference
+ } else if (!reference.startsWith("rowName:")) { // Not a rowName ref; so it's a metadata value reference
MetadataValueService metadataValueService = ContentServiceFactory.getInstance().getMetadataValueService();
MetadataFieldService metadataFieldService =
- ContentServiceFactory.getInstance().getMetadataFieldService();
+ ContentServiceFactory.getInstance().getMetadataFieldService();
int i = reference.indexOf(":");
String mfValue = reference.substring(i + 1);
String mf[] = reference.substring(0, i).split("\\.");
if (mf.length < 2) {
- throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
- "Bad metadata field in reference: '" + reference
- + "' (expected syntax is schema.element[.qualifier])");
+ throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
+ "Bad metadata field in reference: '" + reference
+ + "' (expected syntax is schema.element[.qualifier])");
}
String schema = mf[0];
String element = mf[1];
@@ -1600,13 +1547,13 @@ public class MetadataImport {
MetadataValue mdvVal = mdv.next();
uuid = mdvVal.getDSpaceObject().getID();
if (mdv.hasNext()) {
- throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
- "Ambiguous reference; multiple matches in db: " + reference);
+ throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
+ "Ambiguous reference; multiple matches in db: " + reference);
}
}
} catch (SQLException e) {
- throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
- "Error looking up item by metadata reference: " + reference, e);
+ throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
+ "Error looking up item by metadata reference: " + reference, e);
}
}
// Lookup UUIDs that may have already been processed into the csvRefMap
@@ -1614,24 +1561,25 @@ public class MetadataImport {
// See getMatchingCSVUUIDs() for how the reference param is sourced from the csvRefMap
Set csvUUIDs = getMatchingCSVUUIDs(reference);
if (csvUUIDs.size() > 1) {
- throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
- "Ambiguous reference; multiple matches in csv: " + reference);
+ throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
+ "Ambiguous reference; multiple matches in csv: " + reference);
} else if (csvUUIDs.size() == 1) {
UUID csvUUID = csvUUIDs.iterator().next();
if (csvUUID.equals(uuid)) {
return uuid; // one match from csv and db (same item)
} else if (uuid != null) {
- throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
- "Ambiguous reference; multiple matches in db and csv: " + reference);
+ throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
+ "Ambiguous reference; multiple matches in db and csv: " + reference);
} else {
return csvUUID; // one match from csv
}
} else { // size == 0; the reference does not exist throw an error
if (uuid == null) {
- throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
- "No matches found for reference: " + reference
- + "\nKeep in mind you can only reference entries that are listed before " +
- "this one within the CSV.");
+ throw new MetadataImportException("Error in CSV row " + rowCount + ":\n" +
+ "No matches found for reference: " + reference
+ + "\nKeep in mind you can only reference entries that are " +
+ "listed before " +
+ "this one within the CSV.");
} else {
return uuid; // one match from db
}
@@ -1688,14 +1636,16 @@ public class MetadataImport {
* Validate every relation modification expressed in the CSV.
*
*/
- private void validateExpressedRelations() throws MetadataImportException {
+ private void validateExpressedRelations(Context c) throws MetadataImportException {
for (String targetUUID : entityRelationMap.keySet()) {
String targetType = null;
try {
// Get the type of reference. Attempt lookup in processed map first before looking in archive.
if (entityTypeMap.get(UUID.fromString(targetUUID)) != null) {
targetType = entityTypeService.
- findByEntityType(c, entityTypeMap.get(UUID.fromString(targetUUID))).getLabel();
+ findByEntityType(c,
+ entityTypeMap.get(UUID.fromString(targetUUID)))
+ .getLabel();
} else {
// Target item may be archived; check there.
// Add to errors if Realtionship.type cannot be derived
@@ -1703,18 +1653,19 @@ public class MetadataImport {
if (itemService.find(c, UUID.fromString(targetUUID)) != null) {
targetItem = itemService.find(c, UUID.fromString(targetUUID));
List relTypes = itemService.
- getMetadata(targetItem, "relationship", "type", null, Item.ANY);
+ getMetadata(targetItem, "relationship", "type",
+ null, Item.ANY);
String relTypeValue = null;
if (relTypes.size() > 0) {
relTypeValue = relTypes.get(0).getValue();
targetType = entityTypeService.findByEntityType(c, relTypeValue).getLabel();
} else {
relationValidationErrors.add("Cannot resolve Entity type for target UUID: " +
- targetUUID);
+ targetUUID);
}
} else {
relationValidationErrors.add("Cannot resolve Entity type for target UUID: " +
- targetUUID);
+ targetUUID);
}
}
if (targetType == null) {
@@ -1739,7 +1690,7 @@ public class MetadataImport {
// Attempt lookup in processed map first before looking in archive.
if (entityTypeMap.get(UUID.fromString(originRefererUUID)) != null) {
originType = entityTypeMap.get(UUID.fromString(originRefererUUID));
- validateTypesByTypeByTypeName(targetType, originType, typeName, originRow);
+ validateTypesByTypeByTypeName(c, targetType, originType, typeName, originRow);
} else {
// Origin item may be archived; check there.
// Add to errors if Realtionship.type cannot be derived.
@@ -1747,22 +1698,23 @@ public class MetadataImport {
if (itemService.find(c, UUID.fromString(targetUUID)) != null) {
originItem = itemService.find(c, UUID.fromString(originRefererUUID));
List relTypes = itemService.
- getMetadata(originItem, "relationship", "type", null, Item.ANY);
+ getMetadata(originItem, "relationship",
+ "type", null, Item.ANY);
String relTypeValue = null;
if (relTypes.size() > 0) {
relTypeValue = relTypes.get(0).getValue();
originType = entityTypeService.findByEntityType(c, relTypeValue).getLabel();
- validateTypesByTypeByTypeName(targetType, originType, typeName, originRow);
+ validateTypesByTypeByTypeName(c, targetType, originType, typeName, originRow);
} else {
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
- "Cannot resolve Entity type for reference: "
- + originRefererUUID);
+ "Cannot resolve Entity type for reference: "
+ + originRefererUUID);
}
} else {
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
- "Cannot resolve Entity type for reference: "
- + originRefererUUID + " in row: " + originRow );
+ "Cannot resolve Entity type for reference: "
+ + originRefererUUID + " in row: " + originRow);
}
}
}
@@ -1791,20 +1743,22 @@ public class MetadataImport {
* @param typeName left or right typeName of the respective Relationship.
* @return the UUID of the item.
*/
- private void validateTypesByTypeByTypeName(String targetType, String originType, String typeName, String originRow)
- throws MetadataImportException {
+ private void validateTypesByTypeByTypeName(Context c,
+ String targetType, String originType, String typeName, String originRow)
+ throws MetadataImportException {
try {
RelationshipType foundRelationshipType = null;
List relationshipTypeList = relationshipTypeService.
- findByLeftwardOrRightwardTypeName(c, typeName.split("\\.")[1]);
+ findByLeftwardOrRightwardTypeName(
+ c, typeName.split("\\.")[1]);
// Validate described relationship form the CSV.
foundRelationshipType = matchRelationshipType(relationshipTypeList, targetType, originType, typeName);
if (foundRelationshipType == null) {
relationValidationErrors.add("Error on CSV row " + originRow + ":" + "\n" +
- "No Relationship type found for:\n" +
- "Target type: " + targetType + "\n" +
- "Origin referer type: " + originType + "\n" +
- "with typeName: " + typeName + " for type: " + originType);
+ "No Relationship type found for:\n" +
+ "Target type: " + targetType + "\n" +
+ "Origin referer type: " + originType + "\n" +
+ "with typeName: " + typeName + " for type: " + originType);
}
} catch (SQLException sqle) {
throw new MetadataImportException("Error interacting with database!", sqle);
@@ -1837,7 +1791,7 @@ public class MetadataImport {
continue;
}
if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(originType) &&
- relationshipType.getRightType().getLabel().equalsIgnoreCase(targetType)) {
+ relationshipType.getRightType().getLabel().equalsIgnoreCase(targetType)) {
foundRelationshipType = relationshipType;
}
} else {
@@ -1845,7 +1799,7 @@ public class MetadataImport {
continue;
}
if (relationshipType.getLeftType().getLabel().equalsIgnoreCase(targetType) &&
- relationshipType.getRightType().getLabel().equalsIgnoreCase(originType)) {
+ relationshipType.getRightType().getLabel().equalsIgnoreCase(originType)) {
foundRelationshipType = relationshipType;
}
}
@@ -1853,4 +1807,4 @@ public class MetadataImport {
return foundRelationshipType;
}
-}
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportCLI.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportCLI.java
new file mode 100644
index 0000000000..efc396d68f
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportCLI.java
@@ -0,0 +1,33 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.bulkedit;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.dspace.scripts.handler.DSpaceRunnableHandler;
+
+/**
+ * CLI variant for the {@link MetadataImport} class
+ * This has been made so that we can specify the behaviour of the determineChanges method to be specific for the CLI
+ */
+public class MetadataImportCLI extends MetadataImport {
+
+ @Override
+ protected boolean determineChange(DSpaceRunnableHandler handler) throws IOException {
+ handler.logInfo("Do you want to make these changes? [y/n] ");
+ try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in))) {
+ String yn = bufferedReader.readLine();
+ if ("y".equalsIgnoreCase(yn)) {
+ return true;
+ }
+ return false;
+ }
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportCliScriptConfiguration.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportCliScriptConfiguration.java
new file mode 100644
index 0000000000..3504eddac3
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportCliScriptConfiguration.java
@@ -0,0 +1,16 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.bulkedit;
+
+import org.dspace.scripts.configuration.ScriptConfiguration;
+
+/**
+ * The {@link ScriptConfiguration} for the {@link org.dspace.app.bulkedit.MetadataImportCLI} CLI script
+ */
+public class MetadataImportCliScriptConfiguration extends MetadataImportScriptConfiguration {
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportScriptConfiguration.java b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportScriptConfiguration.java
new file mode 100644
index 0000000000..9ea50b7de5
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/app/bulkedit/MetadataImportScriptConfiguration.java
@@ -0,0 +1,84 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.bulkedit;
+
+import java.io.InputStream;
+import java.sql.SQLException;
+
+import org.apache.commons.cli.Options;
+import org.dspace.authorize.service.AuthorizeService;
+import org.dspace.core.Context;
+import org.dspace.scripts.configuration.ScriptConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * The {@link ScriptConfiguration} for the {@link MetadataImport} script
+ */
+public class MetadataImportScriptConfiguration extends ScriptConfiguration {
+
+ @Autowired
+ private AuthorizeService authorizeService;
+
+ private Class dspaceRunnableClass;
+
+ @Override
+ public Class getDspaceRunnableClass() {
+ return dspaceRunnableClass;
+ }
+
+ /**
+ * Generic setter for the dspaceRunnableClass
+ * @param dspaceRunnableClass The dspaceRunnableClass to be set on this MetadataImportScriptConfiguration
+ */
+ @Override
+ public void setDspaceRunnableClass(Class dspaceRunnableClass) {
+ this.dspaceRunnableClass = dspaceRunnableClass;
+ }
+
+ @Override
+ public boolean isAllowedToExecute(Context context) {
+ try {
+ return authorizeService.isAdmin(context);
+ } catch (SQLException e) {
+ throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
+ }
+ }
+
+ @Override
+ public Options getOptions() {
+ if (options == null) {
+ Options options = new Options();
+
+ options.addOption("f", "file", true, "source file");
+ options.getOption("f").setType(InputStream.class);
+ options.getOption("f").setRequired(true);
+ options.addOption("e", "email", true, "email address or user id of user (required if adding new items)");
+ options.getOption("e").setType(String.class);
+ options.getOption("e").setRequired(true);
+ options.addOption("s", "silent", false,
+ "silent operation - doesn't request confirmation of changes USE WITH CAUTION");
+ options.getOption("s").setType(boolean.class);
+ options.addOption("w", "workflow", false, "workflow - when adding new items, use collection workflow");
+ options.getOption("w").setType(boolean.class);
+ options.addOption("n", "notify", false,
+ "notify - when adding new items using a workflow, send notification emails");
+ options.getOption("n").setType(boolean.class);
+ options.addOption("v", "validate-only", false,
+ "validate - just validate the csv, don't run the import");
+ options.getOption("v").setType(boolean.class);
+ options.addOption("t", "template", false,
+ "template - when adding new items, use the collection template (if it exists)");
+ options.getOption("t").setType(boolean.class);
+ options.addOption("h", "help", false, "help");
+ options.getOption("h").setType(boolean.class);
+
+ super.options = options;
+ }
+ return options;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/app/launcher/ScriptLauncher.java b/dspace-api/src/main/java/org/dspace/app/launcher/ScriptLauncher.java
index ef6b0b538e..6ee62bd904 100644
--- a/dspace-api/src/main/java/org/dspace/app/launcher/ScriptLauncher.java
+++ b/dspace-api/src/main/java/org/dspace/app/launcher/ScriptLauncher.java
@@ -16,9 +16,11 @@ import java.util.TreeMap;
import org.apache.commons.cli.ParseException;
import org.apache.log4j.Logger;
import org.dspace.scripts.DSpaceRunnable;
+import org.dspace.scripts.configuration.ScriptConfiguration;
import org.dspace.scripts.factory.ScriptServiceFactory;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
import org.dspace.scripts.handler.impl.CommandLineDSpaceRunnableHandler;
+import org.dspace.scripts.service.ScriptService;
import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit;
import org.dspace.services.RequestService;
@@ -44,7 +46,8 @@ public class ScriptLauncher {
/**
* Default constructor
*/
- private ScriptLauncher() { }
+ private ScriptLauncher() {
+ }
/**
* Execute the DSpace script launcher
@@ -54,7 +57,7 @@ public class ScriptLauncher {
* @throws FileNotFoundException if file doesn't exist
*/
public static void main(String[] args)
- throws FileNotFoundException, IOException {
+ throws FileNotFoundException, IOException, IllegalAccessException, InstantiationException {
// Initialise the service manager kernel
try {
kernelImpl = DSpaceKernelInit.getKernel(null);
@@ -107,13 +110,18 @@ public class ScriptLauncher {
* @param commandConfigs The Document
* @param dSpaceRunnableHandler The DSpaceRunnableHandler for this execution
* @param kernelImpl The relevant DSpaceKernelImpl
- * @return A 1 or 0 depending on whether the script failed or passed respectively
+ * @return A 1 or 0 depending on whether the script failed or passed respectively
*/
public static int handleScript(String[] args, Document commandConfigs,
- DSpaceRunnableHandler dSpaceRunnableHandler,
- DSpaceKernelImpl kernelImpl) {
+ DSpaceRunnableHandler dSpaceRunnableHandler,
+ DSpaceKernelImpl kernelImpl) throws InstantiationException, IllegalAccessException {
int status;
- DSpaceRunnable script = ScriptServiceFactory.getInstance().getScriptService().getScriptForName(args[0]);
+ ScriptService scriptService = ScriptServiceFactory.getInstance().getScriptService();
+ ScriptConfiguration scriptConfiguration = scriptService.getScriptConfiguration(args[0]);
+ DSpaceRunnable script = null;
+ if (scriptConfiguration != null) {
+ script = scriptService.createDSpaceRunnableForScriptConfiguration(scriptConfiguration);
+ }
if (script != null) {
status = executeScript(args, dSpaceRunnableHandler, script);
} else {
@@ -127,12 +135,12 @@ public class ScriptLauncher {
* @param args The arguments of the script with the script name as first place in the array
* @param dSpaceRunnableHandler The relevant DSpaceRunnableHandler
* @param script The script to be executed
- * @return A 1 or 0 depending on whether the script failed or passed respectively
+ * @return A 1 or 0 depending on whether the script failed or passed respectively
*/
private static int executeScript(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler,
DSpaceRunnable script) {
try {
- script.initialize(args, dSpaceRunnableHandler);
+ script.initialize(args, dSpaceRunnableHandler, null);
script.run();
return 0;
} catch (ParseException e) {
diff --git a/dspace-api/src/main/java/org/dspace/app/util/AuthorizeUtil.java b/dspace-api/src/main/java/org/dspace/app/util/AuthorizeUtil.java
index 39fb713970..ea1fb87ff4 100644
--- a/dspace-api/src/main/java/org/dspace/app/util/AuthorizeUtil.java
+++ b/dspace-api/src/main/java/org/dspace/app/util/AuthorizeUtil.java
@@ -590,8 +590,11 @@ public class AuthorizeUtil {
authorizeManageAdminGroup(context, collection);
return;
}
-
-
+ // if we reach this point, it means that the group is related
+ // to a collection but as it is not the submitters, nor the administrators,
+ // nor a workflow groups it must be a default item/bitstream groups
+ authorizeManageDefaultReadGroup(context, collection);
+ return;
}
if (parentObject.getType() == Constants.COMMUNITY) {
Community community = (Community) parentObject;
@@ -601,4 +604,38 @@ public class AuthorizeUtil {
throw new AuthorizeException("not authorized to manage this group");
}
+
+ /**
+ * This method checks if the community Admin can manage accounts
+ *
+ * @return true if is able
+ */
+ public static boolean canCommunityAdminManageAccounts() {
+ boolean isAble = false;
+ if (AuthorizeConfiguration.canCommunityAdminManagePolicies()
+ || AuthorizeConfiguration.canCommunityAdminManageAdminGroup()
+ || AuthorizeConfiguration.canCommunityAdminManageCollectionPolicies()
+ || AuthorizeConfiguration.canCommunityAdminManageCollectionSubmitters()
+ || AuthorizeConfiguration.canCommunityAdminManageCollectionWorkflows()
+ || AuthorizeConfiguration.canCommunityAdminManageCollectionAdminGroup()) {
+ isAble = true;
+ }
+ return isAble;
+ }
+
+ /**
+ * This method checks if the Collection Admin can manage accounts
+ *
+ * @return true if is able
+ */
+ public static boolean canCollectionAdminManageAccounts() {
+ boolean isAble = false;
+ if (AuthorizeConfiguration.canCollectionAdminManagePolicies()
+ || AuthorizeConfiguration.canCollectionAdminManageSubmitters()
+ || AuthorizeConfiguration.canCollectionAdminManageWorkflows()
+ || AuthorizeConfiguration.canCollectionAdminManageAdminGroup()) {
+ isAble = true;
+ }
+ return isAble;
+ }
}
diff --git a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java
index 2384a260da..07a7ac70d3 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/AuthorizeServiceImpl.java
@@ -430,7 +430,11 @@ public class AuthorizeServiceImpl implements AuthorizeService {
public boolean isCommunityAdmin(Context c) throws SQLException {
EPerson e = c.getCurrentUser();
+ return isCommunityAdmin(c, e);
+ }
+ @Override
+ public boolean isCommunityAdmin(Context c, EPerson e) throws SQLException {
if (e != null) {
List policies = resourcePolicyService.find(c, e,
groupService.allMemberGroups(c, e),
@@ -446,7 +450,11 @@ public class AuthorizeServiceImpl implements AuthorizeService {
public boolean isCollectionAdmin(Context c) throws SQLException {
EPerson e = c.getCurrentUser();
+ return isCollectionAdmin(c, e);
+ }
+ @Override
+ public boolean isCollectionAdmin(Context c, EPerson e) throws SQLException {
if (e != null) {
List policies = resourcePolicyService.find(c, e,
groupService.allMemberGroups(c, e),
diff --git a/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java b/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java
index 9e739e2585..f3ede72ac1 100644
--- a/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java
+++ b/dspace-api/src/main/java/org/dspace/authorize/service/AuthorizeService.java
@@ -213,6 +213,26 @@ public interface AuthorizeService {
public boolean isCollectionAdmin(Context c) throws SQLException;
+ /**
+ * Check to see if a specific user is Community admin
+ *
+ * @param c current context
+ * @param e the user to check
+ * @return true if user is an admin of some community
+ * @throws SQLException
+ */
+ public boolean isCommunityAdmin(Context c, EPerson e) throws SQLException;
+
+ /**
+ * Check to see if a specific user is Collection admin
+ *
+ * @param c current context
+ * @param e the user to check
+ * @return true if user is an admin of some collection
+ * @throws SQLException if database error
+ */
+ public boolean isCollectionAdmin(Context c, EPerson e) throws SQLException;
+
///////////////////////////////////////////////
// policy manipulation methods
///////////////////////////////////////////////
diff --git a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java
index c4f8d288b3..34bf4f5fc1 100644
--- a/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/content/CollectionServiceImpl.java
@@ -17,11 +17,13 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.MissingResourceException;
+import java.util.Set;
import java.util.UUID;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
+import org.apache.solr.client.solrj.util.ClientUtils;
import org.dspace.app.util.AuthorizeUtil;
import org.dspace.authorize.AuthorizeConfiguration;
import org.dspace.authorize.AuthorizeException;
@@ -40,6 +42,13 @@ import org.dspace.core.Context;
import org.dspace.core.I18nUtil;
import org.dspace.core.LogManager;
import org.dspace.core.service.LicenseService;
+import org.dspace.discovery.DiscoverQuery;
+import org.dspace.discovery.DiscoverResult;
+import org.dspace.discovery.IndexableObject;
+import org.dspace.discovery.SearchService;
+import org.dspace.discovery.SearchServiceException;
+import org.dspace.discovery.indexobject.IndexableCollection;
+import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.eperson.service.GroupService;
import org.dspace.eperson.service.SubscribeService;
@@ -100,6 +109,9 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i
@Autowired(required = true)
protected CollectionRoleService collectionRoleService;
+ @Autowired(required = true)
+ protected SearchService searchService;
+
protected CollectionServiceImpl() {
super();
}
@@ -907,4 +919,77 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl i
return role;
}
+ @Override
+ public List findCollectionsWithSubmit(String q, Context context, Community community,
+ int offset, int limit) throws SQLException, SearchServiceException {
+
+ List collections = new ArrayList();
+ DiscoverQuery discoverQuery = new DiscoverQuery();
+ discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
+ discoverQuery.setStart(offset);
+ discoverQuery.setMaxResults(limit);
+ DiscoverResult resp = retrieveCollectionsWithSubmit(context, discoverQuery,community, q);
+ for (IndexableObject solrCollections : resp.getIndexableObjects()) {
+ Collection c = ((IndexableCollection) solrCollections).getIndexedObject();
+ collections.add(c);
+ }
+ return collections;
+ }
+
+ @Override
+ public int countCollectionsWithSubmit(String q, Context context, Community community)
+ throws SQLException, SearchServiceException {
+
+ DiscoverQuery discoverQuery = new DiscoverQuery();
+ discoverQuery.setMaxResults(0);
+ discoverQuery.setDSpaceObjectFilter(IndexableCollection.TYPE);
+ DiscoverResult resp = retrieveCollectionsWithSubmit(context, discoverQuery,community,q);
+ return (int)resp.getTotalSearchResults();
+ }
+
+ /**
+ * Finds all Indexed Collections where the current user has submit rights. If the user is an Admin,
+ * this is all Indexed Collections. Otherwise, it includes those collections where
+ * an indexed "submit" policy lists either the eperson or one of the eperson's groups
+ *
+ * @param context DSpace context
+ * @param discoverQuery
+ * @param community parent community, could be null
+ * @param q limit the returned collection to those with metadata values matching the query
+ * terms. The terms are used to make also a prefix query on SOLR
+ * so it can be used to implement an autosuggest feature over the collection name
+ * @return discovery search result objects
+ * @throws SQLException if something goes wrong
+ * @throws SearchServiceException if search error
+ */
+ private DiscoverResult retrieveCollectionsWithSubmit(Context context, DiscoverQuery discoverQuery,
+ Community community, String q) throws SQLException, SearchServiceException {
+
+ StringBuilder query = new StringBuilder();
+ EPerson currentUser = context.getCurrentUser();
+ if (!authorizeService.isAdmin(context)) {
+ String userId = "";
+ if (currentUser != null) {
+ userId = currentUser.getID().toString();
+ }
+ query.append("submit:(e").append(userId);
+ Set groups = groupService.allMemberGroupsSet(context, currentUser);
+ for (Group group : groups) {
+ query.append(" OR g").append(group.getID());
+ }
+ query.append(")");
+ discoverQuery.addFilterQueries(query.toString());
+ }
+ if (community != null) {
+ discoverQuery.addFilterQueries("location.comm:" + community.getID().toString());
+ }
+ if (StringUtils.isNotBlank(q)) {
+ StringBuilder buildQuery = new StringBuilder();
+ String escapedQuery = ClientUtils.escapeQueryChars(q);
+ buildQuery.append(escapedQuery).append(" OR ").append(escapedQuery).append("*");
+ discoverQuery.setQuery(buildQuery.toString());
+ }
+ DiscoverResult resp = searchService.search(context, discoverQuery);
+ return resp;
+ }
}
diff --git a/dspace-api/src/main/java/org/dspace/content/MetadataDSpaceCsvExportServiceImpl.java b/dspace-api/src/main/java/org/dspace/content/MetadataDSpaceCsvExportServiceImpl.java
new file mode 100644
index 0000000000..85cfcba2e0
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/content/MetadataDSpaceCsvExportServiceImpl.java
@@ -0,0 +1,129 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.content;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import com.google.common.collect.Iterators;
+import org.dspace.app.bulkedit.DSpaceCSV;
+import org.dspace.content.service.ItemService;
+import org.dspace.content.service.MetadataDSpaceCsvExportService;
+import org.dspace.core.Constants;
+import org.dspace.core.Context;
+import org.dspace.handle.factory.HandleServiceFactory;
+import org.dspace.scripts.handler.DSpaceRunnableHandler;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * Implementation of {@link MetadataDSpaceCsvExportService}
+ */
+public class MetadataDSpaceCsvExportServiceImpl implements MetadataDSpaceCsvExportService {
+
+ @Autowired
+ private ItemService itemService;
+
+ @Override
+ public DSpaceCSV handleExport(Context context, boolean exportAllItems, boolean exportAllMetadata, String handle,
+ DSpaceRunnableHandler handler) throws Exception {
+ Iterator toExport = null;
+
+ if (exportAllItems) {
+ handler.logInfo("Exporting whole repository WARNING: May take some time!");
+ toExport = itemService.findAll(context);
+ } else {
+ DSpaceObject dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, handle);
+ if (dso == null) {
+ throw new IllegalArgumentException(
+ "Item '" + handle + "' does not resolve to an item in your repository!");
+ }
+
+ if (dso.getType() == Constants.ITEM) {
+ handler.logInfo("Exporting item '" + dso.getName() + "' (" + handle + ")");
+ List item = new ArrayList<>();
+ item.add((Item) dso);
+ toExport = item.iterator();
+ } else if (dso.getType() == Constants.COLLECTION) {
+ handler.logInfo("Exporting collection '" + dso.getName() + "' (" + handle + ")");
+ Collection collection = (Collection) dso;
+ toExport = itemService.findByCollection(context, collection);
+ } else if (dso.getType() == Constants.COMMUNITY) {
+ handler.logInfo("Exporting community '" + dso.getName() + "' (" + handle + ")");
+ toExport = buildFromCommunity(context, (Community) dso);
+ } else {
+ throw new IllegalArgumentException("Error identifying '" + handle + "'");
+ }
+ }
+
+ DSpaceCSV csv = this.export(context, toExport, exportAllMetadata);
+ return csv;
+ }
+
+ @Override
+ public DSpaceCSV export(Context context, Iterator toExport, boolean exportAll) throws Exception {
+ Context.Mode originalMode = context.getCurrentMode();
+ context.setMode(Context.Mode.READ_ONLY);
+
+ // Process each item
+ DSpaceCSV csv = new DSpaceCSV(exportAll);
+ while (toExport.hasNext()) {
+ Item item = toExport.next();
+ csv.addItem(item);
+ context.uncacheEntity(item);
+ }
+
+ context.setMode(originalMode);
+ // Return the results
+ return csv;
+ }
+
+ @Override
+ public DSpaceCSV export(Context context, Community community, boolean exportAll) throws Exception {
+ return export(context, buildFromCommunity(context, community), exportAll);
+ }
+
+ /**
+ * Build an array list of item ids that are in a community (include sub-communities and collections)
+ *
+ * @param context DSpace context
+ * @param community The community to build from
+ * @return The list of item ids
+ * @throws SQLException if database error
+ */
+ private Iterator buildFromCommunity(Context context, Community community)
+ throws SQLException {
+ // Add all the collections
+ List collections = community.getCollections();
+ Iterator result = null;
+ for (Collection collection : collections) {
+ Iterator items = itemService.findByCollection(context, collection);
+ result = addItemsToResult(result, items);
+
+ }
+ // Add all the sub-communities
+ List communities = community.getSubcommunities();
+ for (Community subCommunity : communities) {
+ Iterator items = buildFromCommunity(context, subCommunity);
+ result = addItemsToResult(result, items);
+ }
+
+ return result;
+ }
+
+ private Iterator addItemsToResult(Iterator result, Iterator items) {
+ if (result == null) {
+ result = items;
+ } else {
+ result = Iterators.concat(result, items);
+ }
+
+ return result;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java
index 5038aef6d7..8637b61703 100644
--- a/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java
+++ b/dspace-api/src/main/java/org/dspace/content/service/CollectionService.java
@@ -20,8 +20,10 @@ import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.core.Context;
+import org.dspace.discovery.SearchServiceException;
import org.dspace.eperson.Group;
+
/**
* Service interface class for the Collection object.
* The implementation of this class is responsible for all business logic calls for the Collection object and is
@@ -354,4 +356,42 @@ public interface CollectionService
*/
Group createDefaultReadGroup(Context context, Collection collection, String typeOfGroupString, int defaultRead)
throws SQLException, AuthorizeException;
+
+ /**
+ * Returns Collections for which the current user has 'submit' privileges.
+ * NOTE: for better performance, this method retrieves its results from an
+ * index (cache) and does not query the database directly.
+ * This means that results may be stale or outdated until DS-4524 is resolved"
+ *
+ * @param q limit the returned collection to those with metadata values matching the query terms.
+ * The terms are used to make also a prefix query on SOLR so it can be used to implement
+ * an autosuggest feature over the collection name
+ * @param context DSpace Context
+ * @param community parent community
+ * @param offset the position of the first result to return
+ * @param limit paging limit
+ * @return discovery search result objects
+ * @throws SQLException if something goes wrong
+ * @throws SearchServiceException if search error
+ */
+ public List findCollectionsWithSubmit(String q, Context context, Community community,
+ int offset, int limit) throws SQLException, SearchServiceException;
+
+ /**
+ * Counts the number of Collection for which the current user has 'submit' privileges.
+ * NOTE: for better performance, this method retrieves its results from an index (cache)
+ * and does not query the database directly.
+ * This means that results may be stale or outdated until DS-4524 is resolved."
+ *
+ * @param q limit the returned collection to those with metadata values matching the query terms.
+ * The terms are used to make also a prefix query on SOLR so it can be used to implement
+ * an autosuggest feature over the collection name
+ * @param context DSpace Context
+ * @param community parent community
+ * @return total collections found
+ * @throws SQLException if something goes wrong
+ * @throws SearchServiceException if search error
+ */
+ public int countCollectionsWithSubmit(String q, Context context, Community community)
+ throws SQLException, SearchServiceException;
}
diff --git a/dspace-api/src/main/java/org/dspace/content/service/MetadataDSpaceCsvExportService.java b/dspace-api/src/main/java/org/dspace/content/service/MetadataDSpaceCsvExportService.java
new file mode 100644
index 0000000000..aeb956fc49
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/content/service/MetadataDSpaceCsvExportService.java
@@ -0,0 +1,58 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.content.service;
+
+import java.util.Iterator;
+
+import org.dspace.app.bulkedit.DSpaceCSV;
+import org.dspace.content.Community;
+import org.dspace.content.Item;
+import org.dspace.core.Context;
+import org.dspace.scripts.handler.DSpaceRunnableHandler;
+
+/**
+ * This is the interface to be implemented by a Service that deals with the exporting of Metadata
+ */
+public interface MetadataDSpaceCsvExportService {
+
+ /**
+ * This method will export DSpaceObject objects depending on the parameters it gets. It can export all the items
+ * in the repository, all the items in a community, all the items in a collection or a specific item. The latter
+ * three are specified by the handle parameter. The entire repository can be exported by defining the
+ * exportAllItems parameter as true
+ * @param context The relevant DSpace context
+ * @param exportAllItems A boolean indicating whether or not the entire repository should be exported
+ * @param exportAllMetadata Defines if all metadata should be exported or only the allowed ones
+ * @param handle The handle for the DSpaceObject to be exported, can be a Community, Collection or Item
+ * @return A DSpaceCSV object containing the exported information
+ * @throws Exception If something goes wrong
+ */
+ public DSpaceCSV handleExport(Context context, boolean exportAllItems, boolean exportAllMetadata,
+ String handle, DSpaceRunnableHandler dSpaceRunnableHandler) throws Exception;
+
+ /**
+ * This method will export all the Items in the given toExport iterator to a DSpaceCSV
+ * @param context The relevant DSpace context
+ * @param toExport The iterator containing the items to export
+ * @param exportAll Defines if all metadata should be exported or only the allowed ones
+ * @return A DSpaceCSV object containing the exported information
+ * @throws Exception If something goes wrong
+ */
+ public DSpaceCSV export(Context context, Iterator toExport, boolean exportAll) throws Exception;
+
+ /**
+ * This method will export all the Items within the given Community to a DSpaceCSV
+ * @param context The relevant DSpace context
+ * @param community The Community that contains the Items to be exported
+ * @param exportAll Defines if all metadata should be exported or only the allowed ones
+ * @return A DSpaceCSV object containing the exported information
+ * @throws Exception If something goes wrong
+ */
+ public DSpaceCSV export(Context context, Community community, boolean exportAll) throws Exception;
+
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/discovery/IndexClient.java b/dspace-api/src/main/java/org/dspace/discovery/IndexClient.java
index 2e7b00a617..4e6fa16177 100644
--- a/dspace-api/src/main/java/org/dspace/discovery/IndexClient.java
+++ b/dspace-api/src/main/java/org/dspace/discovery/IndexClient.java
@@ -14,7 +14,6 @@ import java.util.Optional;
import java.util.UUID;
import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
@@ -30,17 +29,18 @@ import org.dspace.discovery.indexobject.factory.IndexFactory;
import org.dspace.discovery.indexobject.factory.IndexObjectFactoryFactory;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.scripts.DSpaceRunnable;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.dspace.services.factory.DSpaceServicesFactory;
+import org.dspace.utils.DSpace;
/**
* Class used to reindex dspace communities/collections/items into discovery
*/
-public class IndexClient extends DSpaceRunnable {
+public class IndexClient extends DSpaceRunnable {
private Context context;
-
- @Autowired
- private IndexingService indexer;
+ private IndexingService indexer = DSpaceServicesFactory.getInstance().getServiceManager()
+ .getServiceByName(IndexingService.class.getName(),
+ IndexingService.class);
private IndexClientOptions indexClientOptions;
@@ -144,6 +144,12 @@ public class IndexClient extends DSpaceRunnable {
handler.logInfo("Done with indexing");
}
+ @Override
+ public IndexDiscoveryScriptConfiguration getScriptConfiguration() {
+ return new DSpace().getServiceManager().getServiceByName("index-discovery",
+ IndexDiscoveryScriptConfiguration.class);
+ }
+
public void setup() throws ParseException {
try {
context = new Context(Context.Mode.READ_ONLY);
@@ -151,18 +157,8 @@ public class IndexClient extends DSpaceRunnable {
} catch (Exception e) {
throw new ParseException("Unable to create a new DSpace Context: " + e.getMessage());
}
-
indexClientOptions = IndexClientOptions.getIndexClientOption(commandLine);
}
-
- /**
- * Constructor for this class. This will ensure that the Options are created and set appropriately.
- */
- private IndexClient() {
- Options options = IndexClientOptions.constructOptions();
- this.options = options;
- }
-
/**
* Indexes the given object and all children, if applicable.
*
diff --git a/dspace-api/src/main/java/org/dspace/discovery/IndexDiscoveryScriptConfiguration.java b/dspace-api/src/main/java/org/dspace/discovery/IndexDiscoveryScriptConfiguration.java
new file mode 100644
index 0000000000..8bf3cf2aba
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/IndexDiscoveryScriptConfiguration.java
@@ -0,0 +1,58 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.discovery;
+
+import java.sql.SQLException;
+
+import org.apache.commons.cli.Options;
+import org.dspace.authorize.service.AuthorizeService;
+import org.dspace.core.Context;
+import org.dspace.scripts.configuration.ScriptConfiguration;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * The {@link ScriptConfiguration} for the {@link IndexClient} script
+ */
+public class IndexDiscoveryScriptConfiguration extends ScriptConfiguration {
+
+ @Autowired
+ private AuthorizeService authorizeService;
+
+ private Class dspaceRunnableClass;
+
+ @Override
+ public Class getDspaceRunnableClass() {
+ return dspaceRunnableClass;
+ }
+
+ @Override
+ public boolean isAllowedToExecute(Context context) {
+ try {
+ return authorizeService.isAdmin(context);
+ } catch (SQLException e) {
+ throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
+ }
+ }
+
+ @Override
+ public Options getOptions() {
+ if (options == null) {
+ super.options = IndexClientOptions.constructOptions();
+ }
+ return options;
+ }
+
+ /**
+ * Generic setter for the dspaceRunnableClass
+ * @param dspaceRunnableClass The dspaceRunnableClass to be set on this IndexDiscoveryScriptConfiguration
+ */
+ @Override
+ public void setDspaceRunnableClass(Class dspaceRunnableClass) {
+ this.dspaceRunnableClass = dspaceRunnableClass;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/discovery/SolrServiceIndexCollectionSubmittersPlugin.java b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceIndexCollectionSubmittersPlugin.java
new file mode 100644
index 0000000000..ebcaab78af
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/discovery/SolrServiceIndexCollectionSubmittersPlugin.java
@@ -0,0 +1,76 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.discovery;
+
+import java.sql.SQLException;
+import java.util.List;
+
+import org.apache.logging.log4j.Logger;
+import org.apache.solr.common.SolrInputDocument;
+import org.dspace.authorize.ResourcePolicy;
+import org.dspace.authorize.service.AuthorizeService;
+import org.dspace.content.Collection;
+import org.dspace.content.Community;
+import org.dspace.content.factory.ContentServiceFactory;
+import org.dspace.core.Constants;
+import org.dspace.core.Context;
+import org.dspace.core.LogManager;
+import org.dspace.discovery.indexobject.IndexableCollection;
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * The purpose of this plugin is to index all ADD type resource policies related to collections.
+ *
+ * @author Mykhaylo Boychuk (at 4science.it)
+ */
+public class SolrServiceIndexCollectionSubmittersPlugin implements SolrServiceIndexPlugin {
+
+ private static final Logger log = org.apache.logging.log4j.LogManager
+ .getLogger(SolrServiceIndexCollectionSubmittersPlugin.class);
+
+ @Autowired(required = true)
+ protected AuthorizeService authorizeService;
+
+ @Override
+ public void additionalIndex(Context context, IndexableObject idxObj, SolrInputDocument document) {
+ if (idxObj instanceof IndexableCollection) {
+ Collection col = ((IndexableCollection) idxObj).getIndexedObject();
+ if (col != null) {
+ try {
+ String fieldValue = null;
+ Community parent = (Community) ContentServiceFactory.getInstance().getDSpaceObjectService(col)
+ .getParentObject(context, col);
+ while (parent != null) {
+ if (parent.getAdministrators() != null) {
+ fieldValue = "g" + parent.getAdministrators().getID();
+ document.addField("submit", fieldValue);
+ }
+ parent = (Community) ContentServiceFactory.getInstance().getDSpaceObjectService(parent)
+ .getParentObject(context, parent);
+ }
+ List policies = authorizeService.getPoliciesActionFilter(context, col,
+ Constants.ADD);
+ for (ResourcePolicy resourcePolicy : policies) {
+ if (resourcePolicy.getGroup() != null) {
+ fieldValue = "g" + resourcePolicy.getGroup().getID();
+ } else {
+ fieldValue = "e" + resourcePolicy.getEPerson().getID();
+
+ }
+ document.addField("submit", fieldValue);
+ context.uncacheEntity(resourcePolicy);
+ }
+ } catch (SQLException e) {
+ log.error(LogManager.getHeader(context, "Error while indexing resource policies",
+ "Collection: (id " + col.getID() + " type " + col.getName() + ")" ));
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java b/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java
index 7c23216458..4437516315 100644
--- a/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/eperson/GroupServiceImpl.java
@@ -23,7 +23,9 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.dspace.authorize.AuthorizeConfiguration;
import org.dspace.authorize.AuthorizeException;
+import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.service.AuthorizeService;
+import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.content.Collection;
import org.dspace.content.DSpaceObject;
import org.dspace.content.DSpaceObjectServiceImpl;
@@ -76,6 +78,8 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements
@Autowired(required = true)
protected AuthorizeService authorizeService;
+ @Autowired(required = true)
+ protected ResourcePolicyService resourcePolicyService;
protected GroupServiceImpl() {
super();
@@ -654,6 +658,23 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl implements
return collectionService.getParentObject(context, collection);
}
}
+ } else {
+ if (AuthorizeConfiguration.canCollectionAdminManagePolicies()
+ || AuthorizeConfiguration.canCommunityAdminManagePolicies()
+ || AuthorizeConfiguration.canCommunityAdminManageCollectionWorkflows()) {
+ List groups = new ArrayList();
+ groups.add(group);
+ List policies = resourcePolicyService.find(context, null, groups,
+ Constants.DEFAULT_ITEM_READ, Constants.COLLECTION);
+ if (policies.size() > 0) {
+ return policies.get(0).getdSpaceObject();
+ }
+ policies = resourcePolicyService.find(context, null, groups,
+ Constants.DEFAULT_BITSTREAM_READ, Constants.COLLECTION);
+ if (policies.size() > 0) {
+ return policies.get(0).getdSpaceObject();
+ }
+ }
}
}
if (AuthorizeConfiguration.canCommunityAdminManageAdminGroup()) {
diff --git a/dspace-api/src/main/java/org/dspace/license/CCLicense.java b/dspace-api/src/main/java/org/dspace/license/CCLicense.java
index b015e3a9d3..d5d9fe14a2 100644
--- a/dspace-api/src/main/java/org/dspace/license/CCLicense.java
+++ b/dspace-api/src/main/java/org/dspace/license/CCLicense.java
@@ -8,6 +8,8 @@
package org.dspace.license;
+import java.util.List;
+
/**
* @author wbossons
*/
@@ -15,17 +17,17 @@ public class CCLicense {
private String licenseName;
private String licenseId;
- private int order = 0;
+ private List ccLicenseFieldList;
public CCLicense() {
super();
}
- public CCLicense(String licenseId, String licenseName, int order) {
+ public CCLicense(String licenseId, String licenseName, List ccLicenseFieldList) {
super();
this.licenseId = licenseId;
this.licenseName = licenseName;
- this.order = order;
+ this.ccLicenseFieldList = ccLicenseFieldList;
}
public String getLicenseName() {
@@ -44,13 +46,19 @@ public class CCLicense {
this.licenseId = licenseId;
}
- public int getOrder() {
- return this.order;
+ /**
+ * Gets the list of CC License Fields
+ * @return the list of CC License Fields
+ */
+ public List getCcLicenseFieldList() {
+ return ccLicenseFieldList;
}
- public void setOrder(int order) {
- this.order = order;
+ /**
+ * Sets the list of CC License Fields
+ * @param ccLicenseFieldList
+ */
+ public void setCcLicenseFieldList(final List ccLicenseFieldList) {
+ this.ccLicenseFieldList = ccLicenseFieldList;
}
-
-
}
diff --git a/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorService.java b/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorService.java
new file mode 100644
index 0000000000..0c061d2d64
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorService.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.license;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.jdom.Document;
+
+/**
+ * Service interface class for the Creative commons license connector service.
+ * The implementation of this class is responsible for all the calls to the CC license API and parsing the response
+ * The service is autowired by spring
+ */
+public interface CCLicenseConnectorService {
+
+ /**
+ * Retrieves the CC Licenses for the provided language from the CC License API
+ *
+ * @param language - the language to retrieve the licenses for
+ * @return a map of licenses with the id and the license for the provided language
+ */
+ public Map retrieveLicenses(String language);
+
+ /**
+ * Retrieve the CC License URI based on the provided license id, language and answers to the field questions from
+ * the CC License API
+ *
+ * @param licenseId - the ID of the license
+ * @param language - the language for which to retrieve the full answerMap
+ * @param answerMap - the answers to the different field questions
+ * @return the CC License URI
+ */
+ public String retrieveRightsByQuestion(String licenseId,
+ String language,
+ Map answerMap);
+
+ /**
+ * Retrieve the license RDF document based on the license URI
+ *
+ * @param licenseURI - The license URI for which to retrieve the license RDF document
+ * @return the license RDF document
+ * @throws IOException
+ */
+ public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException;
+
+ /**
+ * Retrieve the license Name from the license document
+ *
+ * @param doc - The license document from which to retrieve the license name
+ * @return the license name
+ */
+ public String retrieveLicenseName(final Document doc);
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorServiceImpl.java b/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorServiceImpl.java
new file mode 100644
index 0000000000..a237a91984
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/license/CCLicenseConnectorServiceImpl.java
@@ -0,0 +1,371 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.license;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.text.MessageFormat;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.util.EntityUtils;
+import org.apache.logging.log4j.Logger;
+import org.dspace.services.ConfigurationService;
+import org.jaxen.JaxenException;
+import org.jaxen.jdom.JDOMXPath;
+import org.jdom.Attribute;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.xml.sax.InputSource;
+
+/**
+ * Implementation for the Creative commons license connector service.
+ * This class is responsible for all the calls to the CC license API and parsing the response
+ */
+public class CCLicenseConnectorServiceImpl implements CCLicenseConnectorService, InitializingBean {
+
+ private Logger log = org.apache.logging.log4j.LogManager.getLogger(CCLicenseConnectorServiceImpl.class);
+
+ private CloseableHttpClient client;
+ protected SAXBuilder parser = new SAXBuilder();
+
+ private String postArgument = "answers";
+ private String postAnswerFormat =
+ " " +
+ "{1}" +
+ "" +
+ "{2}" +
+ "" +
+ "";
+
+
+ @Autowired
+ private ConfigurationService configurationService;
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ HttpClientBuilder builder = HttpClientBuilder.create();
+
+ client = builder
+ .disableAutomaticRetries()
+ .setMaxConnTotal(5)
+ .build();
+ }
+
+ /**
+ * Retrieves the CC Licenses for the provided language from the CC License API
+ *
+ * @param language - the language to retrieve the licenses for
+ * @return a map of licenses with the id and the license for the provided language
+ */
+ public Map retrieveLicenses(String language) {
+ String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
+
+ String uri = ccLicenseUrl + "/?locale=" + language;
+ HttpGet httpGet = new HttpGet(uri);
+
+ List licenses;
+ try (CloseableHttpResponse response = client.execute(httpGet)) {
+ licenses = retrieveLicenses(response);
+ } catch (JDOMException | JaxenException | IOException e) {
+ log.error("Error while retrieving the license details using url: " + uri, e);
+ licenses = Collections.emptyList();
+ }
+
+ Map ccLicenses = new HashMap<>();
+
+ for (String license : licenses) {
+
+ String licenseUri = ccLicenseUrl + "/license/" + license;
+ HttpGet licenseHttpGet = new HttpGet(licenseUri);
+ try (CloseableHttpResponse response = client.execute(licenseHttpGet)) {
+ CCLicense ccLicense = retrieveLicenseObject(license, response);
+ ccLicenses.put(ccLicense.getLicenseId(), ccLicense);
+ } catch (JaxenException | JDOMException | IOException e) {
+ log.error("Error while retrieving the license details using url: " + licenseUri, e);
+ }
+ }
+
+ return ccLicenses;
+ }
+
+ /**
+ * Retrieve the list of licenses from the response from the CC License API and remove the licenses configured
+ * to be excluded
+ *
+ * @param response The response from the API
+ * @return a list of license identifiers for which details need to be retrieved
+ * @throws IOException
+ * @throws JaxenException
+ * @throws JDOMException
+ */
+ private List retrieveLicenses(CloseableHttpResponse response)
+ throws IOException, JaxenException, JDOMException {
+
+ List domains = new LinkedList<>();
+ String[] excludedLicenses = configurationService.getArrayProperty("cc.license.classfilter");
+
+
+ String responseString = EntityUtils.toString(response.getEntity());
+ JDOMXPath licenseClassXpath = new JDOMXPath("//licenses/license");
+
+
+ try (StringReader stringReader = new StringReader(responseString)) {
+ InputSource is = new InputSource(stringReader);
+ org.jdom.Document classDoc = this.parser.build(is);
+
+ List elements = licenseClassXpath.selectNodes(classDoc);
+ for (Element element : elements) {
+ String licenseId = getSingleNodeValue(element, "@id");
+ if (StringUtils.isNotBlank(licenseId) && !ArrayUtils.contains(excludedLicenses, licenseId)) {
+ domains.add(licenseId);
+ }
+ }
+ }
+
+ return domains;
+
+ }
+
+ /**
+ * Parse the response for a single CC License and return the corresponding CC License Object
+ *
+ * @param licenseId the license id of the CC License to retrieve
+ * @param response for a specific CC License response
+ * @return the corresponding CC License Object
+ * @throws IOException
+ * @throws JaxenException
+ * @throws JDOMException
+ */
+ private CCLicense retrieveLicenseObject(final String licenseId, CloseableHttpResponse response)
+ throws IOException, JaxenException, JDOMException {
+
+ String responseString = EntityUtils.toString(response.getEntity());
+
+
+ JDOMXPath licenseClassXpath = new JDOMXPath("//licenseclass");
+ JDOMXPath licenseFieldXpath = new JDOMXPath("field");
+
+
+ try (StringReader stringReader = new StringReader(responseString)) {
+ InputSource is = new InputSource(stringReader);
+
+ org.jdom.Document classDoc = this.parser.build(is);
+
+ Object element = licenseClassXpath.selectSingleNode(classDoc);
+ String licenseLabel = getSingleNodeValue(element, "label");
+
+ List ccLicenseFields = new LinkedList<>();
+
+ List licenseFields = licenseFieldXpath.selectNodes(element);
+ for (Element licenseField : licenseFields) {
+ CCLicenseField ccLicenseField = parseLicenseField(licenseField);
+ ccLicenseFields.add(ccLicenseField);
+ }
+
+ return new CCLicense(licenseId, licenseLabel, ccLicenseFields);
+ }
+ }
+
+ private CCLicenseField parseLicenseField(final Element licenseField) throws JaxenException {
+ String id = getSingleNodeValue(licenseField, "@id");
+ String label = getSingleNodeValue(licenseField, "label");
+ String description = getSingleNodeValue(licenseField, "description");
+
+ JDOMXPath enumXpath = new JDOMXPath("enum");
+ List enums = enumXpath.selectNodes(licenseField);
+
+ List ccLicenseFieldEnumList = new LinkedList<>();
+
+ for (Element enumElement : enums) {
+ CCLicenseFieldEnum ccLicenseFieldEnum = parseEnum(enumElement);
+ ccLicenseFieldEnumList.add(ccLicenseFieldEnum);
+ }
+
+ return new CCLicenseField(id, label, description, ccLicenseFieldEnumList);
+
+ }
+
+ private CCLicenseFieldEnum parseEnum(final Element enumElement) throws JaxenException {
+ String id = getSingleNodeValue(enumElement, "@id");
+ String label = getSingleNodeValue(enumElement, "label");
+ String description = getSingleNodeValue(enumElement, "description");
+
+ return new CCLicenseFieldEnum(id, label, description);
+ }
+
+
+ private String getNodeValue(final Object el) {
+ if (el instanceof Element) {
+ return ((Element) el).getValue();
+ } else if (el instanceof Attribute) {
+ return ((Attribute) el).getValue();
+ } else if (el instanceof String) {
+ return (String) el;
+ } else {
+ return null;
+ }
+ }
+
+ private String getSingleNodeValue(final Object t, String query) throws JaxenException {
+ JDOMXPath xpath = new JDOMXPath(query);
+ Object singleNode = xpath.selectSingleNode(t);
+
+ return getNodeValue(singleNode);
+ }
+
+ /**
+ * Retrieve the CC License URI based on the provided license id, language and answers to the field questions from
+ * the CC License API
+ *
+ * @param licenseId - the ID of the license
+ * @param language - the language for which to retrieve the full answerMap
+ * @param answerMap - the answers to the different field questions
+ * @return the CC License URI
+ */
+ public String retrieveRightsByQuestion(String licenseId,
+ String language,
+ Map answerMap) {
+
+ String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
+
+
+ HttpPost httpPost = new HttpPost(ccLicenseUrl + "/license/" + licenseId + "/issue");
+
+
+ String answers = createAnswerString(answerMap);
+ MultipartEntityBuilder builder = MultipartEntityBuilder.create();
+ String text = MessageFormat.format(postAnswerFormat, licenseId, language, answers);
+ builder.addTextBody(postArgument, text);
+
+ HttpEntity multipart = builder.build();
+
+ httpPost.setEntity(multipart);
+
+ try (CloseableHttpResponse response = client.execute(httpPost)) {
+ return retrieveLicenseUri(response);
+ } catch (JDOMException | JaxenException | IOException e) {
+ log.error("Error while retrieving the license uri for license : " + licenseId + " with answers "
+ + answerMap.toString(), e);
+ }
+ return null;
+ }
+
+ /**
+ * Parse the response for the CC License URI request and return the corresponding CC License URI
+ *
+ * @param response for a specific CC License URI response
+ * @return the corresponding CC License URI as a string
+ * @throws IOException
+ * @throws JaxenException
+ * @throws JDOMException
+ */
+ private String retrieveLicenseUri(final CloseableHttpResponse response)
+ throws IOException, JaxenException, JDOMException {
+
+ String responseString = EntityUtils.toString(response.getEntity());
+ JDOMXPath licenseClassXpath = new JDOMXPath("//result/license-uri");
+
+
+ try (StringReader stringReader = new StringReader(responseString)) {
+ InputSource is = new InputSource(stringReader);
+ org.jdom.Document classDoc = this.parser.build(is);
+
+ Object node = licenseClassXpath.selectSingleNode(classDoc);
+ String nodeValue = getNodeValue(node);
+
+ if (StringUtils.isNotBlank(nodeValue)) {
+ return nodeValue;
+ }
+ }
+ return null;
+ }
+
+ private String createAnswerString(final Map parameterMap) {
+ StringBuilder sb = new StringBuilder();
+ for (String key : parameterMap.keySet()) {
+ sb.append("<");
+ sb.append(key);
+ sb.append(">");
+ sb.append(parameterMap.get(key));
+ sb.append("");
+ sb.append(key);
+ sb.append(">");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Retrieve the license RDF document based on the license URI
+ *
+ * @param licenseURI - The license URI for which to retrieve the license RDF document
+ * @return the license RDF document
+ * @throws IOException
+ */
+ @Override
+ public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException {
+ String ccLicenseUrl = configurationService.getProperty("cc.api.rooturl");
+
+ String issueUrl = ccLicenseUrl + "/details?license-uri=" + licenseURI;
+
+ URL request_url;
+ try {
+ request_url = new URL(issueUrl);
+ } catch (MalformedURLException e) {
+ return null;
+ }
+ URLConnection connection = request_url.openConnection();
+ connection.setDoOutput(true);
+ try {
+ // parsing document from input stream
+ InputStream stream = connection.getInputStream();
+ Document doc = parser.build(stream);
+ return doc;
+
+ } catch (Exception e) {
+ log.error("Error while retrieving the license document for URI: " + licenseURI, e);
+ }
+ return null;
+ }
+
+ /**
+ * Retrieve the license Name from the license document
+ *
+ * @param doc - The license document from which to retrieve the license name
+ * @return the license name
+ */
+ public String retrieveLicenseName(final Document doc) {
+ try {
+ return getSingleNodeValue(doc, "//result/license-name");
+ } catch (JaxenException e) {
+ log.error("Error while retrieving the license name from the license document", e);
+ }
+ return null;
+ }
+
+}
diff --git a/dspace-api/src/main/java/org/dspace/license/CCLicenseField.java b/dspace-api/src/main/java/org/dspace/license/CCLicenseField.java
index 6360249f65..8fb6de5478 100644
--- a/dspace-api/src/main/java/org/dspace/license/CCLicenseField.java
+++ b/dspace-api/src/main/java/org/dspace/license/CCLicenseField.java
@@ -7,8 +7,7 @@
*/
package org.dspace.license;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.List;
/**
* Wrapper class for representation of a license field declaration.
@@ -22,7 +21,7 @@ public class CCLicenseField {
private String description = "";
private String type = "";
- private HashMap fieldEnum = null;
+ private List fieldEnum = null;
/**
* Construct a new LicenseField class. Note that after construction,
@@ -31,13 +30,11 @@ public class CCLicenseField {
* @param id The unique identifier for this field; this value will be used in constructing the answers XML.
* @param label The label to use when generating the user interface.
*/
- public CCLicenseField(String id, String label) {
- super();
-
- this.fieldEnum = new HashMap();
-
+ public CCLicenseField(String id, String label, String description, List fieldEnum) {
this.id = id;
this.label = label;
+ this.description = description;
+ this.fieldEnum = fieldEnum;
}
/**
@@ -90,16 +87,12 @@ public class CCLicenseField {
}
/**
- * @return Returns an instance implementing the Map interface;
- * the instance contains a mapping from identifiers to
- * labels for the enumeration values.
- * @see Map
+ * Returns the list of enums of this field
+ * @return the list of enums of this field
*/
- public Map getEnum() {
- return this.fieldEnum;
+ public List getFieldEnum() {
+ return fieldEnum;
}
-
-
}
diff --git a/dspace-api/src/main/java/org/dspace/license/CCLicenseFieldEnum.java b/dspace-api/src/main/java/org/dspace/license/CCLicenseFieldEnum.java
new file mode 100644
index 0000000000..628fcb8354
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/license/CCLicenseFieldEnum.java
@@ -0,0 +1,82 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.license;
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Wrapper class for representation of a license field enum declaration.
+ * A field enum is a single "answer" to the field question
+ */
+public class CCLicenseFieldEnum {
+
+ private String id = "";
+ private String label = "";
+ private String description = "";
+
+ public CCLicenseFieldEnum(String id, String label, String description) {
+ if (StringUtils.isNotBlank(id)) {
+ this.id = id;
+ }
+ if (StringUtils.isNotBlank(label)) {
+ this.label = label;
+ }
+ if (StringUtils.isNotBlank(description)) {
+ this.description = description;
+ }
+
+ }
+
+ /**
+ * Get the id of this enum
+ * @return the id of this enum
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Set the id of this enum
+ * @param id
+ */
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ /**
+ * Get the label of this enum
+ * @return the label of this enum
+ */
+ public String getLabel() {
+ return label;
+ }
+
+ /**
+ * Set the label of this enum
+ * @param label
+ */
+ public void setLabel(final String label) {
+ this.label = label;
+ }
+
+ /**
+ * Get the description of this enum
+ * @return the description of this enum
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Set the description of this enum
+ * @param description
+ */
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/license/CCLookup.java b/dspace-api/src/main/java/org/dspace/license/CCLookup.java
deleted file mode 100644
index c86aa78301..0000000000
--- a/dspace-api/src/main/java/org/dspace/license/CCLookup.java
+++ /dev/null
@@ -1,435 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE and NOTICE files at the root of the source
- * tree and available online at
- *
- * http://www.dspace.org/license/
- */
-package org.dspace.license;
-
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.UnsupportedEncodingException;
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLConnection;
-import java.net.URLEncoder;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-
-import org.apache.logging.log4j.Logger;
-import org.dspace.license.factory.LicenseServiceFactory;
-import org.dspace.license.service.CreativeCommonsService;
-import org.dspace.services.ConfigurationService;
-import org.dspace.services.factory.DSpaceServicesFactory;
-import org.jaxen.JaxenException;
-import org.jaxen.jdom.JDOMXPath;
-import org.jdom.Attribute;
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.JDOMException;
-import org.jdom.input.SAXBuilder;
-
-
-/**
- * A wrapper around Creative Commons REST web services.
- *
- * @author Wendy Bossons
- */
-public class CCLookup {
-
- /**
- * log4j logger
- */
- private static Logger log = org.apache.logging.log4j.LogManager.getLogger(CCLookup.class);
-
- private String cc_root;
- private String jurisdiction;
- private List lcFilter = new ArrayList();
-
- private Document license_doc = null;
- private String rdfString = null;
- private String errorMessage = null;
- private boolean success = false;
-
- private SAXBuilder parser = new SAXBuilder();
- private List licenses = new ArrayList();
- private List licenseFields = new ArrayList();
-
- protected CreativeCommonsService creativeCommonsService = LicenseServiceFactory.getInstance()
- .getCreativeCommonsService();
-
- /**
- * Constructs a new instance with the default web services root.
- */
- public CCLookup() {
- super();
-
- ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
-
- cc_root = configurationService.getProperty("cc.api.rooturl");
-
- String jurisProp = configurationService.getProperty("cc.license.jurisdiction");
- jurisdiction = (jurisProp != null) ? jurisProp : "";
-
- String[] filters = configurationService.getArrayProperty("cc.license.classfilter");
- if (filters != null) {
- for (String name : filters) {
- lcFilter.add(name.trim());
- }
- }
- }
-
- /**
- * Returns the id for a particular CCLicense label. Returns an
- * empty string if no match is found.
- *
- * @param class_label The CCLicense label to find.
- * @return Returns a String containing the License class ID if the label
- * is found; if not found, returns an empty string.
- * @see CCLicense
- */
- public String getLicenseId(String class_label) {
- for (int i = 0; i < this.licenses.size(); i++) {
- if (((CCLicense) this.licenses.get(i)).getLicenseName().equals(class_label)) {
- return ((CCLicense) this.licenses.get(i)).getLicenseId();
- }
- }
-
- return "";
- }
-
- /**
- * Queries the web service for the available licenses.
- *
- * @param language The language to request labels and description strings in.
- * @return Returns a Map of CCLicense objects.
- * @see Map
- * @see CCLicense
- */
- public Collection getLicenses(String language) {
-
- // create XPath expressions
- try {
- JDOMXPath xp_Licenses = new JDOMXPath("//licenses/license");
- JDOMXPath xp_LicenseID = new JDOMXPath("@id");
- URL classUrl = new URL(this.cc_root + "/?locale=" + language);
- Document classDoc = this.parser.build(classUrl);
- // extract the identifiers and labels using XPath
- List results = xp_Licenses.selectNodes(classDoc);
- // populate licenses container
- this.licenses.clear();
- for (int i = 0; i < results.size(); i++) {
- Element license = results.get(i);
- // add if not filtered
- String liD = ((Attribute) xp_LicenseID.selectSingleNode(license)).getValue();
- if (!lcFilter.contains(liD)) {
- this.licenses.add(new CCLicense(liD, license.getText(), i));
- }
- }
- } catch (JaxenException jaxen_e) {
- return null;
- } catch (JDOMException jdom_e) {
- return null;
- } catch (IOException io_e) {
- return null;
- } catch (Exception e) {
- // do nothing... but we should
- return null;
- }
-
- return licenses;
- }
-
-
- /**
- * Queries the web service for a set of licenseFields for a particular license class.
- *
- * @param license A String specifying the CCLicense identifier to
- * retrieve fields for.
- * @param language the locale string
- * @return A Collection of LicenseField objects.
- * @see CCLicense
- */
- public Collection getLicenseFields(String license, String language) {
-
- JDOMXPath xp_LicenseField;
- JDOMXPath xp_LicenseID;
- JDOMXPath xp_FieldType;
- JDOMXPath xp_Description;
- JDOMXPath xp_Label;
- JDOMXPath xp_Enum;
-
- Document fieldDoc;
-
- URL classUrl;
- List results = null;
- List enumOptions = null;
-
- // create XPath expressions
- try {
- xp_LicenseField = new JDOMXPath("//field");
- xp_LicenseID = new JDOMXPath("@id");
- xp_Description = new JDOMXPath("description");
- xp_Label = new JDOMXPath("label");
- xp_FieldType = new JDOMXPath("type");
- xp_Enum = new JDOMXPath("enum");
-
- } catch (JaxenException e) {
- return null;
- }
-
- // retrieve and parse the license class document
- try {
- classUrl = new URL(this.cc_root + "/license/" + license + "?locale=" + language);
- } catch (Exception err) {
- // do nothing... but we should
- return null;
- }
-
- // parse the licenses document
- try {
- fieldDoc = this.parser.build(classUrl);
- } catch (JDOMException e) {
- return null;
- } catch (IOException e) {
- return null;
- }
-
- // reset the field definition container
- this.licenseFields.clear();
-
- // extract the identifiers and labels using XPath
- try {
- results = xp_LicenseField.selectNodes(fieldDoc);
- } catch (JaxenException e) {
- return null;
- }
-
- for (int i = 0; i < results.size(); i++) {
- Element field = (Element) results.get(i);
-
- try {
- // create the field object
- CCLicenseField cclicensefield = new CCLicenseField(
- ((Attribute) xp_LicenseID.selectSingleNode(field)).getValue(),
- ((Element) xp_Label.selectSingleNode(field)).getText());
-
- // extract additional properties
- cclicensefield.setDescription(((Element) xp_Description.selectSingleNode(field)).getText());
- cclicensefield.setType(((Element) xp_FieldType.selectSingleNode(field)).getText());
-
- enumOptions = xp_Enum.selectNodes(field);
-
- for (int j = 0; j < enumOptions.size(); j++) {
- String id = ((Attribute) xp_LicenseID.selectSingleNode(enumOptions.get(j))).getValue();
- String label = ((Element) xp_Label.selectSingleNode(enumOptions.get(j))).getText();
-
- cclicensefield.getEnum().put(id, label);
-
- } // for each enum option
-
- this.licenseFields.add(cclicensefield);
- } catch (JaxenException e) {
- return null;
- }
- }
-
- return licenseFields;
- } // licenseFields
-
- /**
- * Passes a set of "answers" to the web service and retrieves a license.
- *
- * @param licenseId The identifier of the license class being requested.
- * @param answers A Map containing the answers to the license fields;
- * each key is the identifier of a LicenseField, with the value
- * containing the user-supplied answer.
- * @param lang The language to request localized elements in.
- * @throws IOException if IO error
- * @see CCLicense
- * @see Map
- */
- public void issue(String licenseId, Map answers, String lang)
- throws IOException {
-
- // Determine the issue URL
- String issueUrl = this.cc_root + "/license/" + licenseId + "/issue";
- // Assemble the "answers" document
- String answer_doc = "\n" + lang + "\n" + "\n";
- Iterator keys = answers.keySet().iterator();
-
- try {
- String current = (String) keys.next();
-
- while (true) {
- answer_doc += "<" + current + ">" + (String) answers.get(current) + "" + current + ">\n";
- current = (String) keys.next();
- }
-
-
- } catch (NoSuchElementException e) {
- // exception indicates we've iterated through the
- // entire collection; just swallow and continue
- }
- // answer_doc += "\n"; FAILS with jurisdiction argument
- answer_doc += "\n\n";
- String post_data;
-
- try {
- post_data = URLEncoder.encode("answers", "UTF-8") + "=" + URLEncoder.encode(answer_doc, "UTF-8");
- } catch (UnsupportedEncodingException e) {
- return;
- }
-
- URL post_url;
- try {
- post_url = new URL(issueUrl);
- } catch (MalformedURLException e) {
- return;
- }
- URLConnection connection = post_url.openConnection();
- // this will not be needed after I'm done TODO: remove
- connection.setDoOutput(true);
- OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
- writer.write(post_data);
- writer.flush();
- // end TODO
- try {
- // parsing document from input stream
- java.io.InputStream stream = connection.getInputStream();
- this.license_doc = this.parser.build(stream);
- } catch (JDOMException jde) {
- log.warn(jde.getMessage());
- } catch (Exception e) {
- log.warn(e.getCause());
- }
- return;
- } // issue
-
- /**
- * Passes a set of "answers" to the web service and retrieves a license.
- *
- * @param licenseURI The uri of the license.
- *
- * Note: does not support localization in 1.5 -- not yet
- * @throws IOException if IO error
- * @see CCLicense
- * @see Map
- */
- public void issue(String licenseURI)
- throws IOException {
-
- // Determine the issue URL
- // Example: http://api.creativecommons.org/rest/1.5/details?
- // license-uri=http://creativecommons.org/licenses/by-nc-sa/3.0/
- String issueUrl = cc_root + "/details?license-uri=" + licenseURI;
-
- URL request_url;
- try {
- request_url = new URL(issueUrl);
- } catch (MalformedURLException e) {
- return;
- }
- URLConnection connection = request_url.openConnection();
- // this will not be needed after I'm done TODO: remove
- connection.setDoOutput(true);
- try {
- // parsing document from input stream
- java.io.InputStream stream = connection.getInputStream();
- license_doc = this.parser.build(stream);
- } catch (JDOMException jde) {
- log.warn(jde.getMessage());
- } catch (Exception e) {
- log.warn(e.getCause());
- }
- return;
- } // issue
-
- /**
- * Retrieves the URI for the license issued.
- *
- * @return A String containing the URI for the license issued.
- */
- public String getLicenseUrl() {
- String text = null;
- try {
- JDOMXPath xp_LicenseName = new JDOMXPath("//result/license-uri");
- text = ((Element) xp_LicenseName.selectSingleNode(this.license_doc)).getText();
- } catch (Exception e) {
- log.warn(e.getMessage());
- setSuccess(false);
- text = "An error occurred getting the license - uri.";
- } finally {
- return text;
- }
- } // getLicenseUrl
-
- /**
- * Retrieves the human readable name for the license issued.
- *
- * @return A String containing the license name.
- */
- public String getLicenseName() {
- String text = null;
- try {
- JDOMXPath xp_LicenseName = new JDOMXPath("//result/license-name");
- text = ((Element) xp_LicenseName.selectSingleNode(this.license_doc)).getText();
- } catch (Exception e) {
- log.warn(e.getMessage());
- setSuccess(false);
- text = "An error occurred on the license name.";
- } finally {
- return text;
- }
- } // getLicenseName
-
-
- public org.jdom.Document getLicenseDocument() {
- return this.license_doc;
- }
-
- public String getRdf()
- throws IOException {
- String result = "";
- try {
- result = creativeCommonsService.fetchLicenseRDF(license_doc);
- } catch (Exception e) {
- log.warn("An error occurred getting the rdf . . ." + e.getMessage());
- setSuccess(false);
- }
- return result;
- }
-
- public boolean isSuccess() {
- setSuccess(false);
- JDOMXPath xp_Success;
- String text = null;
- try {
- xp_Success = new JDOMXPath("//message");
- text = ((Element) xp_Success.selectSingleNode(this.license_doc)).getText();
- setErrorMessage(text);
- } catch (Exception e) {
- log.warn("There was an issue . . . " + text);
- setSuccess(true);
- }
- return this.success;
- }
-
- private void setSuccess(boolean success) {
- this.success = success;
- }
-
- public String getErrorMessage() {
- return this.errorMessage;
- }
-
- private void setErrorMessage(String errorMessage) {
- this.errorMessage = errorMessage;
- }
-
-}
diff --git a/dspace-api/src/main/java/org/dspace/license/CreativeCommonsServiceImpl.java b/dspace-api/src/main/java/org/dspace/license/CreativeCommonsServiceImpl.java
index 384b82ddc3..40e727d9df 100644
--- a/dspace-api/src/main/java/org/dspace/license/CreativeCommonsServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/license/CreativeCommonsServiceImpl.java
@@ -13,7 +13,10 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
@@ -82,9 +85,18 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
protected BundleService bundleService;
@Autowired(required = true)
protected ItemService itemService;
+ @Autowired
+ protected CCLicenseConnectorService ccLicenseConnectorService;
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
+ private String defaultLanguage;
+ private String jurisdiction;
+ private static final String JURISDICTION_KEY = "jurisdiction";
+
+
+ private Map> ccLicenses;
+
protected CreativeCommonsServiceImpl() {
}
@@ -101,10 +113,14 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
System.setProperty("http.proxyPort", proxyPort);
}
+ ccLicenses = new HashMap<>();
+ defaultLanguage = configurationService.getProperty("cc.license.locale", "en");
+ jurisdiction = configurationService.getProperty("cc.license.jurisdiction", "");
+
try {
templates = TransformerFactory.newInstance().newTemplates(
- new StreamSource(CreativeCommonsServiceImpl.class
- .getResourceAsStream("CreativeCommons.xsl")));
+ new StreamSource(CreativeCommonsServiceImpl.class
+ .getResourceAsStream("CreativeCommons.xsl")));
} catch (TransformerConfigurationException e) {
throw new RuntimeException(e.getMessage(), e);
}
@@ -112,15 +128,10 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
}
- @Override
- public boolean isEnabled() {
- return true;
- }
-
// create the CC bundle if it doesn't exist
// If it does, remove it and create a new one.
protected Bundle getCcBundle(Context context, Item item)
- throws SQLException, AuthorizeException, IOException {
+ throws SQLException, AuthorizeException, IOException {
List bundles = itemService.getBundles(item, CC_BUNDLE_NAME);
if ((bundles.size() > 0) && (bundles.get(0) != null)) {
@@ -131,8 +142,8 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
@Override
public void setLicenseRDF(Context context, Item item, String licenseRdf)
- throws SQLException, IOException,
- AuthorizeException {
+ throws SQLException, IOException,
+ AuthorizeException {
Bundle bundle = getCcBundle(context, item);
// set the format
BitstreamFormat bs_rdf_format = bitstreamFormatService.findByShortDescription(context, "RDF XML");
@@ -144,7 +155,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
@Override
public void setLicense(Context context, Item item,
InputStream licenseStm, String mimeType)
- throws SQLException, IOException, AuthorizeException {
+ throws SQLException, IOException, AuthorizeException {
Bundle bundle = getCcBundle(context, item);
// set the format
@@ -160,17 +171,26 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
Bitstream bs = bitstreamService.create(context, bundle, licenseStm);
bs.setSource(context, CC_BS_SOURCE);
bs.setName(context, (mimeType != null &&
- (mimeType.equalsIgnoreCase("text/xml") ||
- mimeType.equalsIgnoreCase("text/rdf"))) ?
- BSN_LICENSE_RDF : BSN_LICENSE_TEXT);
+ (mimeType.equalsIgnoreCase("text/xml") ||
+ mimeType.equalsIgnoreCase("text/rdf"))) ?
+ BSN_LICENSE_RDF : BSN_LICENSE_TEXT);
bs.setFormat(context, bs_format);
bitstreamService.update(context, bs);
}
+ /**
+ * Removes the license file from the item
+ *
+ * @param context - The relevant DSpace Context
+ * @param item - The item from which the license file needs to be removed
+ * @throws SQLException
+ * @throws IOException
+ * @throws AuthorizeException
+ */
@Override
- public void removeLicense(Context context, Item item)
- throws SQLException, IOException, AuthorizeException {
+ public void removeLicenseFile(Context context, Item item)
+ throws SQLException, IOException, AuthorizeException {
// remove CC license bundle if one exists
List bundles = itemService.getBundles(item, CC_BUNDLE_NAME);
@@ -179,66 +199,74 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
}
}
- @Override
- public boolean hasLicense(Context context, Item item)
- throws SQLException, IOException {
- // try to find CC license bundle
- List bundles = itemService.getBundles(item, CC_BUNDLE_NAME);
-
- if (bundles.size() == 0) {
- return false;
- }
-
- // verify it has correct contents
- try {
- if ((getLicenseURL(context, item) == null)) {
- return false;
- }
- } catch (AuthorizeException ae) {
- return false;
- }
-
- return true;
- }
-
- @Override
- public String getLicenseRDF(Context context, Item item) throws SQLException,
- IOException, AuthorizeException {
- return getStringFromBitstream(context, item, BSN_LICENSE_RDF);
- }
-
@Override
public Bitstream getLicenseRdfBitstream(Item item) throws SQLException,
- IOException, AuthorizeException {
+ IOException, AuthorizeException {
return getBitstream(item, BSN_LICENSE_RDF);
}
@Deprecated
@Override
public Bitstream getLicenseTextBitstream(Item item) throws SQLException,
- IOException, AuthorizeException {
+ IOException, AuthorizeException {
return getBitstream(item, BSN_LICENSE_TEXT);
}
@Override
public String getLicenseURL(Context context, Item item) throws SQLException, IOException, AuthorizeException {
- String licenseUri = getCCField("uri").ccItemValue(item);
+ String licenseUri = getCCField("uri");
if (StringUtils.isNotBlank(licenseUri)) {
- return licenseUri;
+ return getLicenseURI(item);
}
// JSPUI backward compatibility see https://jira.duraspace.org/browse/DS-2604
return getStringFromBitstream(context, item, BSN_LICENSE_URL);
}
+ /**
+ * Returns the stored license uri of the item
+ *
+ * @param item - The item for which to retrieve the stored license uri
+ * @return the stored license uri of the item
+ */
+ @Override
+ public String getLicenseURI(Item item) {
+ String licenseUriField = getCCField("uri");
+ if (StringUtils.isNotBlank(licenseUriField)) {
+ String metadata = itemService.getMetadata(item, licenseUriField);
+ if (StringUtils.isNotBlank(metadata)) {
+ return metadata;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the stored license name of the item
+ *
+ * @param item - The item for which to retrieve the stored license name
+ * @return the stored license name of the item
+ */
+ @Override
+ public String getLicenseName( Item item) {
+ String licenseNameField = getCCField("name");
+ if (StringUtils.isNotBlank(licenseNameField)) {
+ String metadata = itemService.getMetadata(item, licenseNameField);
+ if (StringUtils.isNotBlank(metadata)) {
+ return metadata;
+ }
+ }
+ return null;
+ }
+
@Override
public String fetchLicenseRDF(Document license) {
StringWriter result = new StringWriter();
try {
templates.newTransformer().transform(
- new JDOMSource(license),
- new StreamResult(result)
+ new JDOMSource(license),
+ new StreamResult(result)
);
} catch (TransformerException e) {
throw new IllegalStateException(e.getMessage(), e);
@@ -267,7 +295,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
*/
protected void setBitstreamFromBytes(Context context, Item item, Bundle bundle,
String bitstream_name, BitstreamFormat format, byte[] bytes)
- throws SQLException, IOException, AuthorizeException {
+ throws SQLException, IOException, AuthorizeException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
Bitstream bs = bitstreamService.create(context, bundle, bais);
@@ -297,7 +325,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
*/
protected String getStringFromBitstream(Context context, Item item,
String bitstream_name) throws SQLException, IOException,
- AuthorizeException {
+ AuthorizeException {
byte[] bytes = getBytesFromBitstream(context, item, bitstream_name);
if (bytes == null) {
@@ -320,7 +348,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
* to perform a particular action.
*/
protected Bitstream getBitstream(Item item, String bitstream_name)
- throws SQLException, IOException, AuthorizeException {
+ throws SQLException, IOException, AuthorizeException {
Bundle cc_bundle = null;
// look for the CC bundle
@@ -342,7 +370,7 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
}
protected byte[] getBytesFromBitstream(Context context, Item item, String bitstream_name)
- throws SQLException, IOException, AuthorizeException {
+ throws SQLException, IOException, AuthorizeException {
Bitstream bs = getBitstream(item, bitstream_name);
// no such bitstream
@@ -361,26 +389,322 @@ public class CreativeCommonsServiceImpl implements CreativeCommonsService, Initi
* Returns a metadata field handle for given field Id
*/
@Override
- public LicenseMetadataValue getCCField(String fieldId) {
- return new LicenseMetadataValue(configurationService.getProperty("cc.license." + fieldId));
+ public String getCCField(String fieldId) {
+ return configurationService.getProperty("cc.license." + fieldId);
}
+ /**
+ * Remove license information, delete also the bitstream
+ *
+ * @param context - DSpace Context
+ * @param item - the item
+ * @throws AuthorizeException Exception indicating the current user of the context does not have permission
+ * to perform a particular action.
+ * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
+ * @throws SQLException An exception that provides information on a database access error or other errors.
+ */
@Override
- public void removeLicense(Context context, LicenseMetadataValue uriField,
- LicenseMetadataValue nameField, Item item)
- throws AuthorizeException, IOException, SQLException {
+ public void removeLicense(Context context, Item item)
+ throws AuthorizeException, IOException, SQLException {
+
+ String uriField = getCCField("uri");
+ String nameField = getCCField("name");
+
+ String licenseUri = itemService.getMetadata(item, uriField);
+
// only remove any previous licenses
- String licenseUri = uriField.ccItemValue(item);
if (licenseUri != null) {
- uriField.removeItemValue(context, item, licenseUri);
+ removeLicenseField(context, item, uriField);
if (configurationService.getBooleanProperty("cc.submit.setname")) {
- String licenseName = nameField.keyedItemValue(item, licenseUri);
- nameField.removeItemValue(context, item, licenseName);
+ removeLicenseField(context, item, nameField);
}
if (configurationService.getBooleanProperty("cc.submit.addbitstream")) {
- removeLicense(context, item);
+ removeLicenseFile(context, item);
}
}
}
+ private void removeLicenseField(Context context, Item item, String field) throws SQLException {
+ String[] params = splitField(field);
+ itemService.clearMetadata(context, item, params[0], params[1], params[2], params[3]);
+
+ }
+
+ private void addLicenseField(Context context, Item item, String field, String value) throws SQLException {
+ String[] params = splitField(field);
+ itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], value);
+
+ }
+
+ /**
+ * Find all CC Licenses using the default language found in the configuration
+ *
+ * @return A list of available CC Licenses
+ */
+ @Override
+ public List findAllCCLicenses() {
+ return findAllCCLicenses(defaultLanguage);
+ }
+
+ /**
+ * Find all CC Licenses for the provided language
+ *
+ * @param language - the language for which to find the CC Licenses
+ * @return A list of available CC Licenses for the provided language
+ */
+ @Override
+ public List findAllCCLicenses(String language) {
+
+ if (!ccLicenses.containsKey(language)) {
+ initLicenses(language);
+ }
+ return new LinkedList<>(ccLicenses.get(language).values());
+ }
+
+ /**
+ * Find the CC License corresponding to the provided ID using the default language found in the configuration
+ *
+ * @param id - the ID of the license to be found
+ * @return the corresponding license if found or null when not found
+ */
+ @Override
+ public CCLicense findOne(String id) {
+ return findOne(id, defaultLanguage);
+ }
+
+ /**
+ * Find the CC License corresponding to the provided ID and provided language
+ *
+ * @param id - the ID of the license to be found
+ * @param language - the language for which to find the CC License
+ * @return the corresponding license if found or null when not found
+ */
+ @Override
+ public CCLicense findOne(String id, String language) {
+ if (!ccLicenses.containsKey(language)) {
+ initLicenses(language);
+ }
+ Map licenseMap = ccLicenses.get(language);
+ if (licenseMap.containsKey(id)) {
+ return licenseMap.get(id);
+ }
+ return null;
+ }
+
+ /**
+ * Retrieves the licenses for a specific language and cache them in this service
+ *
+ * @param language - the language for which to find the CC Licenses
+ */
+ private void initLicenses(final String language) {
+ Map licenseMap = ccLicenseConnectorService.retrieveLicenses(language);
+ ccLicenses.put(language, licenseMap);
+ }
+
+ /**
+ * Retrieve the CC License URI for the provided license ID, based on the provided answers, using the default
+ * language found in the configuration
+ *
+ * @param licenseId - the ID of the license
+ * @param answerMap - the answers to the different field questions
+ * @return the corresponding license URI
+ */
+ @Override
+ public String retrieveLicenseUri(String licenseId, Map answerMap) {
+ return retrieveLicenseUri(licenseId, defaultLanguage, answerMap);
+
+ }
+
+ /**
+ * Retrieve the CC License URI for the provided license ID and language based on the provided answers
+ *
+ * @param licenseId - the ID of the license
+ * @param language - the language for which to find the CC License URI
+ * @param answerMap - the answers to the different field questions
+ * @return the corresponding license URI
+ */
+ @Override
+ public String retrieveLicenseUri(String licenseId, String language, Map answerMap) {
+ return ccLicenseConnectorService.retrieveRightsByQuestion(licenseId, language, answerMap);
+
+ }
+
+ /**
+ * Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
+ * corresponding question in the license, using the default language found in the config to check the license
+ *
+ * @param licenseId - the ID of the license
+ * @param fullAnswerMap - the answers to the different field questions
+ * @return whether the information is valid
+ */
+ @Override
+ public boolean verifyLicenseInformation(String licenseId, Map fullAnswerMap) {
+ return verifyLicenseInformation(licenseId, defaultLanguage, fullAnswerMap);
+ }
+
+ /**
+ * Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
+ * corresponding question in the license, using the provided language to check the license
+ *
+ * @param licenseId - the ID of the license
+ * @param language - the language for which to retrieve the full answerMap
+ * @param fullAnswerMap - the answers to the different field questions
+ * @return whether the information is valid
+ */
+ @Override
+ public boolean verifyLicenseInformation(String licenseId, String language, Map fullAnswerMap) {
+ CCLicense ccLicense = findOne(licenseId, language);
+
+ List ccLicenseFieldList = ccLicense.getCcLicenseFieldList();
+
+ for (String field : fullAnswerMap.keySet()) {
+ CCLicenseField ccLicenseField = findCCLicenseField(field, ccLicenseFieldList);
+ if (ccLicenseField == null) {
+ return false;
+ }
+ if (!containsAnswerEnum(fullAnswerMap.get(field), ccLicenseField)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Retrieve the full answer map containing empty values when an answer for a field was not provided in the
+ * answerMap, using the default language found in the configuration
+ *
+ * @param licenseId - the ID of the license
+ * @param answerMap - the answers to the different field questions
+ * @return the answerMap supplemented with all other license fields with a blank answer
+ */
+ @Override
+ public Map retrieveFullAnswerMap(String licenseId, Map answerMap) {
+ return retrieveFullAnswerMap(licenseId, defaultLanguage, answerMap);
+ }
+
+ /**
+ * Retrieve the full answer map for a provided language, containing empty values when an answer for a field was not
+ * provided in the answerMap.
+ *
+ * @param licenseId - the ID of the license
+ * @param language - the language for which to retrieve the full answerMap
+ * @param answerMap - the answers to the different field questions
+ * @return the answerMap supplemented with all other license fields with a blank answer for the provided language
+ */
+ @Override
+ public Map retrieveFullAnswerMap(String licenseId, String language, Map answerMap) {
+ CCLicense ccLicense = findOne(licenseId, language);
+ if (ccLicense == null) {
+ return null;
+ }
+ Map fullParamMap = new HashMap<>(answerMap);
+ List ccLicenseFieldList = ccLicense.getCcLicenseFieldList();
+ for (CCLicenseField ccLicenseField : ccLicenseFieldList) {
+ if (!fullParamMap.containsKey(ccLicenseField.getId())) {
+ fullParamMap.put(ccLicenseField.getId(), "");
+ }
+ }
+
+ updateJurisdiction(fullParamMap);
+
+ return fullParamMap;
+ }
+
+ private void updateJurisdiction(final Map fullParamMap) {
+ if (fullParamMap.containsKey(JURISDICTION_KEY)) {
+ fullParamMap.put(JURISDICTION_KEY, jurisdiction);
+ }
+ }
+
+ private boolean containsAnswerEnum(final String enumAnswer, final CCLicenseField ccLicenseField) {
+ List fieldEnums = ccLicenseField.getFieldEnum();
+ for (CCLicenseFieldEnum fieldEnum : fieldEnums) {
+ if (StringUtils.equals(fieldEnum.getId(), enumAnswer)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private CCLicenseField findCCLicenseField(final String field, final List ccLicenseFieldList) {
+ for (CCLicenseField ccLicenseField : ccLicenseFieldList) {
+ if (StringUtils.equals(ccLicenseField.getId(), field)) {
+ return ccLicenseField;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Update the license of the item with a new one based on the provided license URI
+ *
+ * @param context - The relevant DSpace context
+ * @param licenseUri - The license URI to be used in the update
+ * @param item - The item for which to update the license
+ * @return true when the update was successful, false when not
+ * @throws AuthorizeException
+ * @throws SQLException
+ */
+ @Override
+ public boolean updateLicense(final Context context, final String licenseUri, final Item item)
+ throws AuthorizeException, SQLException {
+ try {
+ Document doc = ccLicenseConnectorService.retrieveLicenseRDFDoc(licenseUri);
+ if (doc == null) {
+ return false;
+ }
+ String licenseName = ccLicenseConnectorService.retrieveLicenseName(doc);
+ if (StringUtils.isBlank(licenseName)) {
+ return false;
+ }
+
+ removeLicense(context, item);
+ addLicense(context, item, licenseUri, licenseName, doc);
+
+ return true;
+
+ } catch (IOException e) {
+ log.error("Error while updating the license of item: " + item.getID(), e);
+ }
+ return false;
+ }
+
+ /**
+ * Add a new license to the item
+ *
+ * @param context - The relevant Dspace context
+ * @param item - The item to which the license will be added
+ * @param licenseUri - The license URI to add
+ * @param licenseName - The license name to add
+ * @param doc - The license to document to add
+ * @throws SQLException
+ * @throws IOException
+ * @throws AuthorizeException
+ */
+ @Override
+ public void addLicense(Context context, Item item, String licenseUri, String licenseName, Document doc)
+ throws SQLException, IOException, AuthorizeException {
+ String uriField = getCCField("uri");
+ String nameField = getCCField("name");
+
+ addLicenseField(context, item, uriField, licenseUri);
+ if (configurationService.getBooleanProperty("cc.submit.addbitstream")) {
+ setLicenseRDF(context, item, fetchLicenseRDF(doc));
+ }
+ if (configurationService.getBooleanProperty("cc.submit.setname")) {
+ addLicenseField(context, item, nameField, licenseName);
+ }
+ }
+
+ private String[] splitField(String fieldName) {
+ String[] params = new String[4];
+ String[] fParams = fieldName.split("\\.");
+ for (int i = 0; i < fParams.length; i++) {
+ params[i] = fParams[i];
+ }
+ params[3] = Item.ANY;
+ return params;
+ }
+
}
diff --git a/dspace-api/src/main/java/org/dspace/license/LicenseMetadataValue.java b/dspace-api/src/main/java/org/dspace/license/LicenseMetadataValue.java
deleted file mode 100644
index ec5c9e447b..0000000000
--- a/dspace-api/src/main/java/org/dspace/license/LicenseMetadataValue.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/**
- * The contents of this file are subject to the license and copyright
- * detailed in the LICENSE and NOTICE files at the root of the source
- * tree and available online at
- *
- * http://www.dspace.org/license/
- */
-package org.dspace.license;
-
-import java.io.IOException;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.List;
-
-import org.dspace.authorize.AuthorizeException;
-import org.dspace.content.Item;
-import org.dspace.content.MetadataValue;
-import org.dspace.content.factory.ContentServiceFactory;
-import org.dspace.content.service.ItemService;
-import org.dspace.core.Context;
-
-/**
- * Helper class for using CC-related Metadata fields
- *
- * @author kevinvandevelde at atmire.com
- */
-public class LicenseMetadataValue {
-
- protected final ItemService itemService;
- // Shibboleth for Creative Commons license data - i.e. characters that reliably indicate CC in a URI
- protected static final String ccShib = "creativecommons";
-
- private String[] params = new String[4];
-
- public LicenseMetadataValue(String fieldName) {
- if (fieldName != null && fieldName.length() > 0) {
- String[] fParams = fieldName.split("\\.");
- for (int i = 0; i < fParams.length; i++) {
- params[i] = fParams[i];
- }
- params[3] = Item.ANY;
- }
- itemService = ContentServiceFactory.getInstance().getItemService();
- }
-
- /**
- * Returns first value that matches Creative Commons 'shibboleth',
- * or null if no matching values.
- * NB: this method will succeed only for metadata fields holding CC URIs
- *
- * @param item - the item to read
- * @return value - the first CC-matched value, or null if no such value
- */
- public String ccItemValue(Item item) {
- List dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]);
- for (MetadataValue dcvalue : dcvalues) {
- if ((dcvalue.getValue()).indexOf(ccShib) != -1) {
- // return first value that matches the shib
- return dcvalue.getValue();
- }
- }
- return null;
- }
-
- /**
- * Returns the value that matches the value mapped to the passed key if any.
- * NB: this only delivers a license name (if present in field) given a license URI
- *
- * @param item - the item to read
- * @param key - the key for desired value
- * @return value - the value associated with key or null if no such value
- * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
- * @throws SQLException An exception that provides information on a database access error or other errors.
- * @throws AuthorizeException Exception indicating the current user of the context does not have permission
- * to perform a particular action.
- */
- public String keyedItemValue(Item item, String key)
- throws AuthorizeException, IOException, SQLException {
- CCLookup ccLookup = new CCLookup();
- ccLookup.issue(key);
- String matchValue = ccLookup.getLicenseName();
- List dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]);
- for (MetadataValue dcvalue : dcvalues) {
- if (dcvalue.getValue().equals(matchValue)) {
- return dcvalue.getValue();
- }
- }
- return null;
- }
-
- /**
- * Removes the passed value from the set of values for the field in passed item.
- *
- * @param context The relevant DSpace Context.
- * @param item - the item to update
- * @param value - the value to remove
- * @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
- * @throws SQLException An exception that provides information on a database access error or other errors.
- * @throws AuthorizeException Exception indicating the current user of the context does not have permission
- * to perform a particular action.
- */
- public void removeItemValue(Context context, Item item, String value)
- throws AuthorizeException, IOException, SQLException {
- if (value != null) {
- List dcvalues = itemService.getMetadata(item, params[0], params[1], params[2], params[3]);
- ArrayList arrayList = new ArrayList();
- for (MetadataValue dcvalue : dcvalues) {
- if (!dcvalue.getValue().equals(value)) {
- arrayList.add(dcvalue.getValue());
- }
- }
- itemService.clearMetadata(context, item, params[0], params[1], params[2], params[3]);
- itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], arrayList);
- }
- }
-
- /**
- * Adds passed value to the set of values for the field in passed item.
- *
- * @param context The relevant DSpace Context.
- * @param item - the item to update
- * @param value - the value to add in this field
- * @throws SQLException An exception that provides information on a database access error or other errors.
- */
- public void addItemValue(Context context, Item item, String value) throws SQLException {
- itemService.addMetadata(context, item, params[0], params[1], params[2], params[3], value);
- }
-
-}
diff --git a/dspace-api/src/main/java/org/dspace/license/service/CreativeCommonsService.java b/dspace-api/src/main/java/org/dspace/license/service/CreativeCommonsService.java
index c99c38a127..fa32cb75ca 100644
--- a/dspace-api/src/main/java/org/dspace/license/service/CreativeCommonsService.java
+++ b/dspace-api/src/main/java/org/dspace/license/service/CreativeCommonsService.java
@@ -10,12 +10,14 @@ package org.dspace.license.service;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Bitstream;
import org.dspace.content.Item;
import org.dspace.core.Context;
-import org.dspace.license.LicenseMetadataValue;
+import org.dspace.license.CCLicense;
import org.jdom.Document;
/**
@@ -29,13 +31,6 @@ public interface CreativeCommonsService {
public static final String CC_BUNDLE_NAME = "CC-LICENSE";
- /**
- * Simple accessor for enabling of CC
- *
- * @return is CC enabled?
- */
- public boolean isEnabled();
-
/**
* setLicenseRDF
*
@@ -50,7 +45,7 @@ public interface CreativeCommonsService {
* to perform a particular action.
*/
public void setLicenseRDF(Context context, Item item, String licenseRdf)
- throws SQLException, IOException, AuthorizeException;
+ throws SQLException, IOException, AuthorizeException;
/**
@@ -72,19 +67,40 @@ public interface CreativeCommonsService {
*/
public void setLicense(Context context, Item item,
InputStream licenseStm, String mimeType)
- throws SQLException, IOException, AuthorizeException;
+ throws SQLException, IOException, AuthorizeException;
- public void removeLicense(Context context, Item item)
- throws SQLException, IOException, AuthorizeException;
+ /**
+ * Removes the license file from the item
+ *
+ * @param context - The relevant DSpace Context
+ * @param item - The item from which the license file needs to be removed
+ * @throws SQLException
+ * @throws IOException
+ * @throws AuthorizeException
+ */
+ public void removeLicenseFile(Context context, Item item)
+ throws SQLException, IOException, AuthorizeException;
- public boolean hasLicense(Context context, Item item)
- throws SQLException, IOException;
public String getLicenseURL(Context context, Item item)
- throws SQLException, IOException, AuthorizeException;
+ throws SQLException, IOException, AuthorizeException;
- public String getLicenseRDF(Context context, Item item)
- throws SQLException, IOException, AuthorizeException;
+
+ /**
+ * Returns the stored license uri of the item
+ *
+ * @param item - The item for which to retrieve the stored license uri
+ * @return the stored license uri of the item
+ */
+ public String getLicenseURI(Item item);
+
+ /**
+ * Returns the stored license name of the item
+ *
+ * @param item - The item for which to retrieve the stored license name
+ * @return the stored license name of the item
+ */
+ public String getLicenseName(Item item);
/**
* Get Creative Commons license RDF, returning Bitstream object.
@@ -97,7 +113,7 @@ public interface CreativeCommonsService {
* to perform a particular action.
*/
public Bitstream getLicenseRdfBitstream(Item item)
- throws SQLException, IOException, AuthorizeException;
+ throws SQLException, IOException, AuthorizeException;
/**
* Get Creative Commons license Text, returning Bitstream object.
@@ -112,7 +128,7 @@ public interface CreativeCommonsService {
* is no longer stored (see https://jira.duraspace.org/browse/DS-2604)
*/
public Bitstream getLicenseTextBitstream(Item item)
- throws SQLException, IOException, AuthorizeException;
+ throws SQLException, IOException, AuthorizeException;
/**
* Get a few license-specific properties. We expect these to be cached at
@@ -121,7 +137,7 @@ public interface CreativeCommonsService {
* @param fieldId name of the property.
* @return its value.
*/
- public LicenseMetadataValue getCCField(String fieldId);
+ public String getCCField(String fieldId);
/**
* Apply same transformation on the document to retrieve only the most
@@ -138,15 +154,134 @@ public interface CreativeCommonsService {
* Remove license information, delete also the bitstream
*
* @param context - DSpace Context
- * @param uriField - the metadata field for license uri
- * @param nameField - the metadata field for license name
* @param item - the item
* @throws AuthorizeException Exception indicating the current user of the context does not have permission
* to perform a particular action.
* @throws IOException A general class of exceptions produced by failed or interrupted I/O operations.
* @throws SQLException An exception that provides information on a database access error or other errors.
*/
- public void removeLicense(Context context, LicenseMetadataValue uriField,
- LicenseMetadataValue nameField, Item item)
- throws AuthorizeException, IOException, SQLException;
+ public void removeLicense(Context context, Item item)
+ throws AuthorizeException, IOException, SQLException;
+
+ /**
+ * Find all CC Licenses using the default language found in the configuration
+ *
+ * @return A list of available CC Licenses
+ */
+ public List findAllCCLicenses();
+
+ /**
+ * Find all CC Licenses for the provided language
+ *
+ * @param language - the language for which to find the CC Licenses
+ * @return A list of available CC Licenses for the provided language
+ */
+ public List findAllCCLicenses(String language);
+
+ /**
+ * Find the CC License corresponding to the provided ID using the default language found in the configuration
+ *
+ * @param id - the ID of the license to be found
+ * @return the corresponding license if found or null when not found
+ */
+ public CCLicense findOne(String id);
+
+ /**
+ * Find the CC License corresponding to the provided ID and provided language
+ *
+ * @param id - the ID of the license to be found
+ * @param language - the language for which to find the CC License
+ * @return the corresponding license if found or null when not found
+ */
+ public CCLicense findOne(String id, String language);
+
+ /**
+ * Retrieve the CC License URI for the provided license ID, based on the provided answers, using the default
+ * language found in the configuration
+ *
+ * @param licenseId - the ID of the license
+ * @param answerMap - the answers to the different field questions
+ * @return the corresponding license URI
+ */
+ public String retrieveLicenseUri(String licenseId, Map answerMap);
+
+ /**
+ * Retrieve the CC License URI for the provided license ID and language based on the provided answers
+ *
+ * @param licenseId - the ID of the license
+ * @param language - the language for which to find the CC License URI
+ * @param answerMap - the answers to the different field questions
+ * @return the corresponding license URI
+ */
+ public String retrieveLicenseUri(String licenseId, String language, Map answerMap);
+
+ /**
+ * Retrieve the full answer map containing empty values when an answer for a field was not provided in the
+ * answerMap, using the default language found in the configuration
+ *
+ * @param licenseId - the ID of the license
+ * @param answerMap - the answers to the different field questions
+ * @return the answerMap supplemented with all other license fields with a blank answer
+ */
+ public Map retrieveFullAnswerMap(String licenseId, Map answerMap);
+
+ /**
+ * Retrieve the full answer map for a provided language, containing empty values when an answer for a field was not
+ * provided in the answerMap.
+ *
+ * @param licenseId - the ID of the license
+ * @param language - the language for which to retrieve the full answerMap
+ * @param answerMap - the answers to the different field questions
+ * @return the answerMap supplemented with all other license fields with a blank answer for the provided language
+ */
+ public Map retrieveFullAnswerMap(String licenseId, String language, Map answerMap);
+
+ /**
+ * Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
+ * corresponding question in the license, using the default language found in the config to check the license
+ *
+ * @param licenseId - the ID of the license
+ * @param fullAnswerMap - the answers to the different field questions
+ * @return whether the information is valid
+ */
+ public boolean verifyLicenseInformation(String licenseId, Map fullAnswerMap);
+
+ /**
+ * Verify whether the answer map contains a valid response to all field questions and no answers that don't have a
+ * corresponding question in the license, using the provided language to check the license
+ *
+ * @param licenseId - the ID of the license
+ * @param language - the language for which to retrieve the full answerMap
+ * @param fullAnswerMap - the answers to the different field questions
+ * @return whether the information is valid
+ */
+ public boolean verifyLicenseInformation(String licenseId, String language, Map fullAnswerMap);
+
+ /**
+ * Update the license of the item with a new one based on the provided license URI
+ *
+ * @param context - The relevant DSpace context
+ * @param licenseUri - The license URI to be used in the update
+ * @param item - The item for which to update the license
+ * @return true when the update was successful, false when not
+ * @throws AuthorizeException
+ * @throws SQLException
+ */
+ public boolean updateLicense(final Context context, String licenseUri, final Item item)
+ throws AuthorizeException, SQLException;
+
+ /**
+ * Add a new license to the item
+ *
+ * @param context - The relevant Dspace context
+ * @param item - The item to which the license will be added
+ * @param licenseUri - The license URI to add
+ * @param licenseName - The license name to add
+ * @param doc - The license to document to add
+ * @throws SQLException
+ * @throws IOException
+ * @throws AuthorizeException
+ */
+ public void addLicense(Context context, Item item, String licenseUri, String licenseName, Document doc)
+ throws SQLException, IOException, AuthorizeException;
}
diff --git a/dspace-api/src/main/java/org/dspace/scripts/DSpaceRunnable.java b/dspace-api/src/main/java/org/dspace/scripts/DSpaceRunnable.java
index 4ce1c5063a..d0fffdb57d 100644
--- a/dspace-api/src/main/java/org/dspace/scripts/DSpaceRunnable.java
+++ b/dspace-api/src/main/java/org/dspace/scripts/DSpaceRunnable.java
@@ -7,70 +7,72 @@
*/
package org.dspace.scripts;
-import java.sql.SQLException;
+import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
-import org.dspace.authorize.service.AuthorizeService;
-import org.dspace.core.Context;
+import org.apache.commons.lang3.StringUtils;
+import org.dspace.eperson.EPerson;
+import org.dspace.scripts.configuration.ScriptConfiguration;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Required;
/**
- * This abstract class is the class that should be extended by each script.
- * it provides the basic variables to be hold by the script as well as the means to initialize, parse and run the script
- * Every DSpaceRunnable that is implemented in this way should be defined in the scripts.xml config file as a bean
+ * This is the class that should be extended for each Script. This class will contain the logic needed to run and it'll
+ * fetch the information that it needs from the {@link ScriptConfiguration} provided through the diamond operators.
+ * This will be the dspaceRunnableClass for the {@link ScriptConfiguration} beans. Specifically created for each
+ * script
+ * @param
*/
-public abstract class DSpaceRunnable implements Runnable {
+public abstract class DSpaceRunnable implements Runnable {
- /**
- * The name of the script
- */
- private String name;
- /**
- * The description of the script
- */
- private String description;
/**
* The CommandLine object for the script that'll hold the information
*/
protected CommandLine commandLine;
+
/**
- * The possible options for this script
+ * This EPerson identifier variable is the uuid of the eperson that's running the script
*/
- protected Options options;
+ private UUID epersonIdentifier;
+
/**
* The handler that deals with this script. This handler can currently either be a RestDSpaceRunnableHandler or
* a CommandlineDSpaceRunnableHandler depending from where the script is called
*/
protected DSpaceRunnableHandler handler;
- @Autowired
- private AuthorizeService authorizeService;
+ /**
+ * This method will return the Configuration that the implementing DSpaceRunnable uses
+ * @return The {@link ScriptConfiguration} that this implementing DspaceRunnable uses
+ */
+ public abstract T getScriptConfiguration();
- public String getName() {
- return name;
+
+ private void setHandler(DSpaceRunnableHandler dSpaceRunnableHandler) {
+ this.handler = dSpaceRunnableHandler;
}
- @Required
- public void setName(String name) {
- this.name = name;
- }
-
- public String getDescription() {
- return description;
- }
-
- @Required
- public void setDescription(String description) {
- this.description = description;
- }
-
- public Options getOptions() {
- return options;
+ /**
+ * This method sets the appropriate DSpaceRunnableHandler depending on where it was ran from and it parses
+ * the arguments given to the script
+ * @param args The arguments given to the script
+ * @param dSpaceRunnableHandler The DSpaceRunnableHandler object that defines from where the script was ran
+ * @param currentUser
+ * @throws ParseException If something goes wrong
+ */
+ public void initialize(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler,
+ EPerson currentUser) throws ParseException {
+ if (currentUser != null) {
+ this.setEpersonIdentifier(currentUser.getID());
+ }
+ this.setHandler(dSpaceRunnableHandler);
+ this.parse(args);
}
/**
@@ -80,18 +82,16 @@ public abstract class DSpaceRunnable implements Runnable {
* @throws ParseException If something goes wrong
*/
private void parse(String[] args) throws ParseException {
- commandLine = new DefaultParser().parse(getOptions(), args);
+ commandLine = new DefaultParser().parse(getScriptConfiguration().getOptions(), args);
setup();
}
/**
- * This method will call upon the {@link DSpaceRunnableHandler#printHelp(Options, String)} method with the script's
- * options and name
+ * This method has to be included in every script and handles the setup of the script by parsing the CommandLine
+ * and setting the variables
+ * @throws ParseException If something goes wrong
*/
- public void printHelp() {
- handler.printHelp(options, name);
- }
-
+ public abstract void setup() throws ParseException;
/**
* This is the run() method from the Runnable interface that we implement. This method will handle the running
@@ -108,22 +108,6 @@ public abstract class DSpaceRunnable implements Runnable {
}
}
- private void setHandler(DSpaceRunnableHandler dSpaceRunnableHandler) {
- this.handler = dSpaceRunnableHandler;
- }
-
- /**
- * This method sets the appropriate DSpaceRunnableHandler depending on where it was ran from and it parses
- * the arguments given to the script
- * @param args The arguments given to the script
- * @param dSpaceRunnableHandler The DSpaceRunnableHandler object that defines from where the script was ran
- * @throws ParseException If something goes wrong
- */
- public void initialize(String[] args, DSpaceRunnableHandler dSpaceRunnableHandler) throws ParseException {
- this.setHandler(dSpaceRunnableHandler);
- this.parse(args);
- }
-
/**
* This method has to be included in every script and this will be the main execution block for the script that'll
* contain all the logic needed
@@ -132,25 +116,46 @@ public abstract class DSpaceRunnable implements Runnable {
public abstract void internalRun() throws Exception;
/**
- * This method has to be included in every script and handles the setup of the script by parsing the CommandLine
- * and setting the variables
- * @throws ParseException If something goes wrong
+ * This method will call upon the {@link DSpaceRunnableHandler#printHelp(Options, String)} method with the script's
+ * options and name
*/
- public abstract void setup() throws ParseException;
+ public void printHelp() {
+ handler.printHelp(getScriptConfiguration().getOptions(), getScriptConfiguration().getName());
+ }
/**
- * This method will return if the script is allowed to execute in the given context. This is by default set
- * to the currentUser in the context being an admin, however this can be overwritten by each script individually
- * if different rules apply
- * @param context The relevant DSpace context
- * @return A boolean indicating whether the script is allowed to execute or not
+ * This method will traverse all the options and it'll grab options defined as an InputStream type to then save
+ * the filename specified by that option in a list of Strings that'll be returned in the end
+ * @return The list of Strings representing filenames from the options given to the script
*/
- public boolean isAllowedToExecute(Context context) {
- try {
- return authorizeService.isAdmin(context);
- } catch (SQLException e) {
- handler.logError("Error occured when trying to verify permissions for script: " + name);
+ public List getFileNamesFromInputStreamOptions() {
+ List fileNames = new LinkedList<>();
+
+ for (Option option : getScriptConfiguration().getOptions().getOptions()) {
+ if (option.getType() == InputStream.class &&
+ StringUtils.isNotBlank(commandLine.getOptionValue(option.getOpt()))) {
+ fileNames.add(commandLine.getOptionValue(option.getOpt()));
+ }
}
- return false;
+
+ return fileNames;
+ }
+
+ /**
+ * Generic getter for the epersonIdentifier
+ * This EPerson identifier variable is the uuid of the eperson that's running the script
+ * @return the epersonIdentifier value of this DSpaceRunnable
+ */
+ public UUID getEpersonIdentifier() {
+ return epersonIdentifier;
+ }
+
+ /**
+ * Generic setter for the epersonIdentifier
+ * This EPerson identifier variable is the uuid of the eperson that's running the script
+ * @param epersonIdentifier The epersonIdentifier to be set on this DSpaceRunnable
+ */
+ public void setEpersonIdentifier(UUID epersonIdentifier) {
+ this.epersonIdentifier = epersonIdentifier;
}
}
diff --git a/dspace-api/src/main/java/org/dspace/scripts/Process.java b/dspace-api/src/main/java/org/dspace/scripts/Process.java
index bc9204d429..c58669e6d9 100644
--- a/dspace-api/src/main/java/org/dspace/scripts/Process.java
+++ b/dspace-api/src/main/java/org/dspace/scripts/Process.java
@@ -8,6 +8,7 @@
package org.dspace.scripts;
import java.util.Date;
+import java.util.LinkedList;
import java.util.List;
import javax.persistence.Column;
import javax.persistence.Entity;
@@ -80,6 +81,8 @@ public class Process implements ReloadableEntity {
@Temporal(TemporalType.TIMESTAMP)
private Date creationTime;
+ public static final String BITSTREAM_TYPE_METADATAFIELD = "dspace.process.filetype";
+
protected Process() {
}
@@ -174,6 +177,9 @@ public class Process implements ReloadableEntity {
* @return The Bitstreams that are used or created by the process
*/
public List getBitstreams() {
+ if (bitstreams == null) {
+ bitstreams = new LinkedList<>();
+ }
return bitstreams;
}
diff --git a/dspace-api/src/main/java/org/dspace/scripts/ProcessServiceImpl.java b/dspace-api/src/main/java/org/dspace/scripts/ProcessServiceImpl.java
index cb5a5c9944..1cdf3505db 100644
--- a/dspace-api/src/main/java/org/dspace/scripts/ProcessServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/scripts/ProcessServiceImpl.java
@@ -7,18 +7,33 @@
*/
package org.dspace.scripts;
+import java.io.IOException;
+import java.io.InputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import java.util.regex.Pattern;
+import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
+import org.dspace.authorize.AuthorizeException;
+import org.dspace.authorize.service.AuthorizeService;
+import org.dspace.content.Bitstream;
+import org.dspace.content.Item;
+import org.dspace.content.MetadataField;
+import org.dspace.content.MetadataValue;
import org.dspace.content.ProcessStatus;
import org.dspace.content.dao.ProcessDAO;
+import org.dspace.content.service.BitstreamFormatService;
+import org.dspace.content.service.BitstreamService;
+import org.dspace.content.service.MetadataFieldService;
+import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.LogManager;
import org.dspace.eperson.EPerson;
@@ -35,6 +50,18 @@ public class ProcessServiceImpl implements ProcessService {
@Autowired
private ProcessDAO processDAO;
+ @Autowired
+ private BitstreamService bitstreamService;
+
+ @Autowired
+ private BitstreamFormatService bitstreamFormatService;
+
+ @Autowired
+ private AuthorizeService authorizeService;
+
+ @Autowired
+ private MetadataFieldService metadataFieldService;
+
@Override
public Process create(Context context, EPerson ePerson, String scriptName,
List parameters) throws SQLException {
@@ -113,11 +140,35 @@ public class ProcessServiceImpl implements ProcessService {
}
@Override
- public void delete(Context context, Process process) throws SQLException {
+ public void appendFile(Context context, Process process, InputStream is, String type, String fileName)
+ throws IOException, SQLException, AuthorizeException {
+ Bitstream bitstream = bitstreamService.create(context, is);
+ if (getBitstream(context, process, type) != null) {
+ throw new IllegalArgumentException("Cannot create another file of type: " + type + " for this process" +
+ " with id: " + process.getID());
+ }
+ bitstream.setName(context, fileName);
+ bitstreamService.setFormat(context, bitstream, bitstreamFormatService.guessFormat(context, bitstream));
+ MetadataField dspaceProcessFileTypeField = metadataFieldService
+ .findByString(context, Process.BITSTREAM_TYPE_METADATAFIELD, '.');
+ bitstreamService.addMetadata(context, bitstream, dspaceProcessFileTypeField, null, type);
+ authorizeService.addPolicy(context, bitstream, Constants.READ, context.getCurrentUser());
+ authorizeService.addPolicy(context, bitstream, Constants.WRITE, context.getCurrentUser());
+ authorizeService.addPolicy(context, bitstream, Constants.DELETE, context.getCurrentUser());
+ bitstreamService.update(context, bitstream);
+ process.addBitstream(bitstream);
+ update(context, process);
+ }
+
+ @Override
+ public void delete(Context context, Process process) throws SQLException, IOException, AuthorizeException {
+
+ for (Bitstream bitstream : ListUtils.emptyIfNull(process.getBitstreams())) {
+ bitstreamService.delete(context, bitstream);
+ }
processDAO.delete(context, process);
log.info(LogManager.getHeader(context, "process_delete", "Process with ID " + process.getID()
+ " and name " + process.getName() + " has been deleted"));
-
}
@Override
@@ -141,8 +192,57 @@ public class ProcessServiceImpl implements ProcessService {
return parameterList;
}
+ @Override
+ public Bitstream getBitstreamByName(Context context, Process process, String bitstreamName) {
+ for (Bitstream bitstream : getBitstreams(context, process)) {
+ if (StringUtils.equals(bitstream.getName(), bitstreamName)) {
+ return bitstream;
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public Bitstream getBitstream(Context context, Process process, String type) {
+ List allBitstreams = process.getBitstreams();
+
+ if (type == null) {
+ return null;
+ } else {
+ if (allBitstreams != null) {
+ for (Bitstream bitstream : allBitstreams) {
+ if (StringUtils.equals(bitstreamService.getMetadata(bitstream,
+ Process.BITSTREAM_TYPE_METADATAFIELD), type)) {
+ return bitstream;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public List getBitstreams(Context context, Process process) {
+ return process.getBitstreams();
+ }
+
public int countTotal(Context context) throws SQLException {
return processDAO.countRows(context);
}
+ @Override
+ public List getFileTypesForProcessBitstreams(Context context, Process process) {
+ List list = getBitstreams(context, process);
+ Set fileTypesSet = new HashSet<>();
+ for (Bitstream bitstream : list) {
+ List metadata = bitstreamService.getMetadata(bitstream,
+ Process.BITSTREAM_TYPE_METADATAFIELD, Item.ANY);
+ if (metadata != null && !metadata.isEmpty()) {
+ fileTypesSet.add(metadata.get(0).getValue());
+ }
+ }
+ return new ArrayList<>(fileTypesSet);
+ }
+
}
diff --git a/dspace-api/src/main/java/org/dspace/scripts/ScriptServiceImpl.java b/dspace-api/src/main/java/org/dspace/scripts/ScriptServiceImpl.java
index e2a6acf3a8..4eb7cdbbc1 100644
--- a/dspace-api/src/main/java/org/dspace/scripts/ScriptServiceImpl.java
+++ b/dspace-api/src/main/java/org/dspace/scripts/ScriptServiceImpl.java
@@ -7,33 +7,46 @@
*/
package org.dspace.scripts;
+import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.stream.Collectors;
-import org.apache.commons.lang3.StringUtils;
import org.dspace.core.Context;
+import org.dspace.kernel.ServiceManager;
+import org.dspace.scripts.configuration.ScriptConfiguration;
import org.dspace.scripts.service.ScriptService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
/**
* The implementation for the {@link ScriptService}
*/
public class ScriptServiceImpl implements ScriptService {
+ private static final Logger log = LoggerFactory.getLogger(ScriptServiceImpl.class);
@Autowired
- private List dSpaceRunnables;
+ private ServiceManager serviceManager;
@Override
- public DSpaceRunnable getScriptForName(String name) {
- return dSpaceRunnables.stream()
- .filter(dSpaceRunnable -> StringUtils.equalsIgnoreCase(dSpaceRunnable.getName(), name))
- .findFirst()
- .orElse(null);
+ public ScriptConfiguration getScriptConfiguration(String name) {
+ return serviceManager.getServiceByName(name, ScriptConfiguration.class);
}
@Override
- public List getDSpaceRunnables(Context context) {
- return dSpaceRunnables.stream().filter(
- dSpaceRunnable -> dSpaceRunnable.isAllowedToExecute(context)).collect(Collectors.toList());
+ public List getScriptConfigurations(Context context) {
+ return serviceManager.getServicesByType(ScriptConfiguration.class).stream().filter(
+ scriptConfiguration -> scriptConfiguration.isAllowedToExecute(context)).collect(Collectors.toList());
+ }
+
+ @Override
+ public DSpaceRunnable createDSpaceRunnableForScriptConfiguration(ScriptConfiguration scriptToExecute)
+ throws IllegalAccessException, InstantiationException {
+ try {
+ return (DSpaceRunnable) scriptToExecute.getDspaceRunnableClass().getDeclaredConstructor().newInstance();
+ } catch (InvocationTargetException | NoSuchMethodException e) {
+ log.error(e.getMessage(), e);
+ throw new RuntimeException(e);
+ }
}
}
diff --git a/dspace-api/src/main/java/org/dspace/scripts/configuration/ScriptConfiguration.java b/dspace-api/src/main/java/org/dspace/scripts/configuration/ScriptConfiguration.java
new file mode 100644
index 0000000000..4b15c22f44
--- /dev/null
+++ b/dspace-api/src/main/java/org/dspace/scripts/configuration/ScriptConfiguration.java
@@ -0,0 +1,92 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.scripts.configuration;
+
+import org.apache.commons.cli.Options;
+import org.dspace.core.Context;
+import org.dspace.scripts.DSpaceRunnable;
+import org.springframework.beans.factory.BeanNameAware;
+
+/**
+ * This class represents an Abstract class that a ScriptConfiguration can inherit to further implement this
+ * and represent a script's configuration
+ */
+public abstract class ScriptConfiguration implements BeanNameAware {
+
+ /**
+ * The possible options for this script
+ */
+ protected Options options;
+
+ private String description;
+
+ private String name;
+
+ /**
+ * Generic getter for the description
+ * @return the description value of this ScriptConfiguration
+ */
+ public String getDescription() {
+ return description;
+ }
+
+ /**
+ * Generic setter for the description
+ * @param description The description to be set on this ScriptConfiguration
+ */
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ /**
+ * Generic getter for the name
+ * @return the name value of this ScriptConfiguration
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Generic setter for the name
+ * @param name The name to be set on this ScriptConfiguration
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Generic getter for the dspaceRunnableClass
+ * @return the dspaceRunnableClass value of this ScriptConfiguration
+ */
+ public abstract Class getDspaceRunnableClass();
+
+ /**
+ * Generic setter for the dspaceRunnableClass
+ * @param dspaceRunnableClass The dspaceRunnableClass to be set on this IndexDiscoveryScriptConfiguration
+ */
+ public abstract void setDspaceRunnableClass(Class dspaceRunnableClass);
+ /**
+ * This method will return if the script is allowed to execute in the given context. This is by default set
+ * to the currentUser in the context being an admin, however this can be overwritten by each script individually
+ * if different rules apply
+ * @param context The relevant DSpace context
+ * @return A boolean indicating whether the script is allowed to execute or not
+ */
+ public abstract boolean isAllowedToExecute(Context context);
+
+ /**
+ * The getter for the options of the Script
+ * @return the options value of this ScriptConfiguration
+ */
+ public abstract Options getOptions();
+
+ @Override
+ public void setBeanName(String beanName) {
+ this.name = beanName;
+ }
+}
diff --git a/dspace-api/src/main/java/org/dspace/scripts/handler/DSpaceRunnableHandler.java b/dspace-api/src/main/java/org/dspace/scripts/handler/DSpaceRunnableHandler.java
index 01ca2fafd9..078ba6bfa2 100644
--- a/dspace-api/src/main/java/org/dspace/scripts/handler/DSpaceRunnableHandler.java
+++ b/dspace-api/src/main/java/org/dspace/scripts/handler/DSpaceRunnableHandler.java
@@ -7,9 +7,14 @@
*/
package org.dspace.scripts.handler;
+import java.io.IOException;
+import java.io.InputStream;
import java.sql.SQLException;
+import java.util.Optional;
import org.apache.commons.cli.Options;
+import org.dspace.authorize.AuthorizeException;
+import org.dspace.core.Context;
/**
* This is an interface meant to be implemented by any DSpaceRunnableHandler to specify specific execution methods
@@ -78,4 +83,28 @@ public interface DSpaceRunnableHandler {
* @param name The name of the script
*/
public void printHelp(Options options, String name);
+
+ /**
+ * This method will grab the InputStream for the file defined by the given file name. The exact implementation will
+ * differ based on whether it's a REST call or CommandLine call. The REST Call will look for Bitstreams in the
+ * Database whereas the CommandLine call will look on the filesystem
+ * @param context The relevant DSpace context
+ * @param fileName The filename for the file that holds the InputStream
+ * @return The InputStream for the file defined by the given file name
+ * @throws IOException If something goes wrong
+ * @throws AuthorizeException If something goes wrong
+ */
+ public Optional getFileStream(Context context, String fileName) throws IOException, AuthorizeException;
+
+ /**
+ * This method will write the InputStream to either a file on the filesystem or a bitstream in the database
+ * depending on whether it's coming from a CommandLine call or REST call respectively
+ * @param context The relevant DSpace context
+ * @param fileName The filename
+ * @param inputStream The inputstream to be written
+ * @param type The type of the file
+ * @throws IOException If something goes wrong
+ */
+ public void writeFilestream(Context context, String fileName, InputStream inputStream, String type)
+ throws IOException, SQLException, AuthorizeException;
}
diff --git a/dspace-api/src/main/java/org/dspace/scripts/handler/impl/CommandLineDSpaceRunnableHandler.java b/dspace-api/src/main/java/org/dspace/scripts/handler/impl/CommandLineDSpaceRunnableHandler.java
index 97925c1843..6775b9a455 100644
--- a/dspace-api/src/main/java/org/dspace/scripts/handler/impl/CommandLineDSpaceRunnableHandler.java
+++ b/dspace-api/src/main/java/org/dspace/scripts/handler/impl/CommandLineDSpaceRunnableHandler.java
@@ -7,9 +7,16 @@
*/
package org.dspace.scripts.handler.impl;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Optional;
+
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Options;
+import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.Logger;
+import org.dspace.core.Context;
import org.dspace.scripts.handler.DSpaceRunnableHandler;
/**
@@ -84,4 +91,20 @@ public class CommandLineDSpaceRunnableHandler implements DSpaceRunnableHandler {
formatter.printHelp(name, options);
}
}
+
+ @Override
+ public Optional getFileStream(Context context, String fileName) throws IOException {
+ File file = new File(fileName);
+ if (!(file.exists() && file.isFile())) {
+ return Optional.empty();
+ }
+ return Optional.of(FileUtils.openInputStream(file));
+ }
+
+ @Override
+ public void writeFilestream(Context context, String fileName, InputStream inputStream, String type)
+ throws IOException {
+ File file = new File(fileName);
+ FileUtils.copyInputStreamToFile(inputStream, file);
+ }
}
diff --git a/dspace-api/src/main/java/org/dspace/scripts/service/ProcessService.java b/dspace-api/src/main/java/org/dspace/scripts/service/ProcessService.java
index e277ab32f4..80a6ec932b 100644
--- a/dspace-api/src/main/java/org/dspace/scripts/service/ProcessService.java
+++ b/dspace-api/src/main/java/org/dspace/scripts/service/ProcessService.java
@@ -7,9 +7,13 @@
*/
package org.dspace.scripts.service;
+import java.io.IOException;
+import java.io.InputStream;
import java.sql.SQLException;
import java.util.List;
+import org.dspace.authorize.AuthorizeException;
+import org.dspace.content.Bitstream;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.scripts.DSpaceCommandLineParameter;
@@ -104,13 +108,28 @@ public interface ProcessService {
*/
public void complete(Context context, Process process) throws SQLException;
+ /**
+ * The method will create a bitstream from the given inputstream with the given type as metadata and given name
+ * as name and attach it to the given process
+ * @param context The relevant DSpace context
+ * @param process The process for which the bitstream will be made
+ * @param is The inputstream for the bitstream
+ * @param type The type of the bitstream
+ * @param fileName The name of the bitstream
+ * @throws IOException If something goes wrong
+ * @throws SQLException If something goes wrong
+ * @throws AuthorizeException If something goes wrong
+ */
+ public void appendFile(Context context, Process process, InputStream is, String type, String fileName)
+ throws IOException, SQLException, AuthorizeException;
+
/**
* This method will delete the given Process object from the database
* @param context The relevant DSpace context
* @param process The Process object to be deleted
* @throws SQLException If something goes wrong
*/
- public void delete(Context context, Process process) throws SQLException;
+ public void delete(Context context, Process process) throws SQLException, IOException, AuthorizeException;
/**
* This method will be used to update the given Process object in the database
@@ -128,6 +147,32 @@ public interface ProcessService {
*/
public List getParameters(Process process);
+ /**
+ * This method will return the Bitstream that matches the given name for the given Process
+ * @param context The relevant DSpace context
+ * @param process The process that should hold the requested Bitstream
+ * @param bitstreamName The name of the requested Bitstream
+ * @return The Bitstream from the given Process that matches the given bitstream name
+ */
+ public Bitstream getBitstreamByName(Context context, Process process, String bitstreamName);
+
+ /**
+ * This method will return the Bitstream for a given process with a given type
+ * @param context The relevant DSpace context
+ * @param process The process that holds the Bitstreams to be searched in
+ * @param type The type that the Bitstream must have
+ * @return The Bitstream of the given type for the given Process
+ */
+ public Bitstream getBitstream(Context context, Process process, String type);
+
+ /**
+ * This method will return all the Bitstreams for a given process
+ * @param context The relevant DSpace context
+ * @param process The process that holds the Bitstreams to be searched in
+ * @return The list of Bitstreams
+ */
+ public List getBitstreams(Context context, Process process);
+
/**
* Returns the total amount of Process objects in the dataase
* @param context The relevant DSpace context
@@ -136,4 +181,12 @@ public interface ProcessService {
*/
int countTotal(Context context) throws SQLException;
+ /**
+ * This will return a list of Strings where each String represents the type of a Bitstream in the Process given
+ * @param context The DSpace context
+ * @param process The Process object that we'll use to find the bitstreams
+ * @return A list of Strings where each String represents a fileType that is in the Process
+ */
+ public List getFileTypesForProcessBitstreams(Context context, Process process);
+
}
diff --git a/dspace-api/src/main/java/org/dspace/scripts/service/ScriptService.java b/dspace-api/src/main/java/org/dspace/scripts/service/ScriptService.java
index fc680bd612..3716123822 100644
--- a/dspace-api/src/main/java/org/dspace/scripts/service/ScriptService.java
+++ b/dspace-api/src/main/java/org/dspace/scripts/service/ScriptService.java
@@ -11,6 +11,7 @@ import java.util.List;
import org.dspace.core.Context;
import org.dspace.scripts.DSpaceRunnable;
+import org.dspace.scripts.configuration.ScriptConfiguration;
/**
* This service will deal with logic to handle DSpaceRunnable objects
@@ -18,16 +19,29 @@ import org.dspace.scripts.DSpaceRunnable;
public interface ScriptService {
/**
- * This method will return the DSpaceRunnable that has the name that's equal to the name given in the parameters
+ * This method will return the ScriptConfiguration that has the name that's equal to the name given in the
+ * parameters
* @param name The name that the script has to match
- * @return The matching DSpaceRunnable script
+ * @return The matching ScriptConfiguration
*/
- DSpaceRunnable getScriptForName(String name);
+ ScriptConfiguration getScriptConfiguration(String name);
/**
- * This method will return a list of DSpaceRunnable objects for which the given Context is authorized to use them
+ * This method will return a list of ScriptConfiguration objects for which the given Context is authorized
* @param context The relevant DSpace context
- * @return The list of accessible DSpaceRunnable scripts for this context
+ * @return The list of accessible ScriptConfiguration scripts for this context
*/
- List getDSpaceRunnables(Context context);
+ List getScriptConfigurations(Context context);
+
+ /**
+ * This method will create a new instance of the DSpaceRunnable that's linked with this Scriptconfiguration
+ * It'll grab the DSpaceRunnable class from the ScriptConfiguration's variables and create a new instance of it
+ * to return
+ * @param scriptToExecute The relevant ScriptConfiguration
+ * @return The new instance of the DSpaceRunnable class
+ * @throws IllegalAccessException If something goes wrong
+ * @throws InstantiationException If something goes wrong
+ */
+ DSpaceRunnable createDSpaceRunnableForScriptConfiguration(ScriptConfiguration scriptToExecute)
+ throws IllegalAccessException, InstantiationException;
}
diff --git a/dspace-api/src/test/data/dspaceFolder/assetstore/testImport.csv b/dspace-api/src/test/data/dspaceFolder/assetstore/testImport.csv
new file mode 100644
index 0000000000..cb658de4ed
--- /dev/null
+++ b/dspace-api/src/test/data/dspaceFolder/assetstore/testImport.csv
@@ -0,0 +1,2 @@
+id,collection,dc.contributor.author
++,"123456789/2","Donald, SmithImported"
diff --git a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml
index de19ef7287..d78b14c437 100644
--- a/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml
+++ b/dspace-api/src/test/data/dspaceFolder/config/item-submission.xml
@@ -82,9 +82,9 @@
-
+ submit.progressbar.CClicense
+ org.dspace.app.rest.submit.step.CCLicenseStep
+ cclicense
-
+
diff --git a/dspace-api/src/test/data/dspaceFolder/config/local.cfg b/dspace-api/src/test/data/dspaceFolder/config/local.cfg
index 3c4b4a839d..51ce1a0165 100644
--- a/dspace-api/src/test/data/dspaceFolder/config/local.cfg
+++ b/dspace-api/src/test/data/dspaceFolder/config/local.cfg
@@ -108,3 +108,15 @@ plugin.sequence.java.util.Collection = \
java.util.LinkedList, \
java.util.Stack, \
java.util.TreeSet
+
+###########################################
+# PROPERTIES USED TO TEST CONFIGURATION #
+# PROPERTY EXPOSURE VIA REST #
+###########################################
+rest.properties.exposed = configuration.exposed.single.value
+rest.properties.exposed = configuration.exposed.array.value
+rest.properties.exposed = configuration.not.existing
+
+configuration.not.exposed = secret_value
+configuration.exposed.single.value = public_value
+configuration.exposed.array.value = public_value_1, public_value_2
diff --git a/dspace-api/src/test/data/dspaceFolder/config/spring/api/scripts.xml b/dspace-api/src/test/data/dspaceFolder/config/spring/api/scripts.xml
index b28d45ec18..30fb69a3c4 100644
--- a/dspace-api/src/test/data/dspaceFolder/config/spring/api/scripts.xml
+++ b/dspace-api/src/test/data/dspaceFolder/config/spring/api/scripts.xml
@@ -4,13 +4,23 @@
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java b/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java
index 1ddba1a011..9cb664fb78 100644
--- a/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java
+++ b/dspace-api/src/test/java/org/dspace/app/bulkedit/DSpaceCSVTest.java
@@ -18,6 +18,7 @@ import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;
+import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.AbstractUnitTest;
import org.junit.Test;
@@ -67,7 +68,7 @@ public class DSpaceCSVTest extends AbstractUnitTest {
out = null;
// Test the CSV parsing was OK
- DSpaceCSV dcsv = new DSpaceCSV(new File(filename), context);
+ DSpaceCSV dcsv = new DSpaceCSV(FileUtils.openInputStream(new File(filename)), context);
String[] lines = dcsv.getCSVLinesAsStringArray();
assertThat("testDSpaceCSV Good CSV", lines.length, equalTo(8));
@@ -96,7 +97,7 @@ public class DSpaceCSVTest extends AbstractUnitTest {
// Test the CSV parsing was OK
try {
- dcsv = new DSpaceCSV(new File(filename), context);
+ dcsv = new DSpaceCSV(FileUtils.openInputStream(new File(filename)), context);
lines = dcsv.getCSVLinesAsStringArray();
fail("An exception should have been thrown due to bad CSV");
@@ -124,7 +125,7 @@ public class DSpaceCSVTest extends AbstractUnitTest {
// Test the CSV parsing was OK
try {
- dcsv = new DSpaceCSV(new File(filename), context);
+ dcsv = new DSpaceCSV(FileUtils.openInputStream(new File(filename)), context);
lines = dcsv.getCSVLinesAsStringArray();
fail("An exception should have been thrown due to bad CSV");
diff --git a/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataExportTest.java b/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataExportTest.java
new file mode 100644
index 0000000000..9594e2a2b1
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataExportTest.java
@@ -0,0 +1,71 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.bulkedit;
+
+import static junit.framework.TestCase.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.io.IOUtils;
+import org.dspace.AbstractIntegrationTest;
+import org.dspace.app.launcher.ScriptLauncher;
+import org.dspace.app.scripts.handler.impl.TestDSpaceRunnableHandler;
+import org.dspace.content.Collection;
+import org.dspace.content.Community;
+import org.dspace.content.Item;
+import org.dspace.content.WorkspaceItem;
+import org.dspace.content.factory.ContentServiceFactory;
+import org.dspace.content.service.CollectionService;
+import org.dspace.content.service.CommunityService;
+import org.dspace.content.service.InstallItemService;
+import org.dspace.content.service.ItemService;
+import org.dspace.content.service.WorkspaceItemService;
+import org.dspace.services.ConfigurationService;
+import org.dspace.services.factory.DSpaceServicesFactory;
+import org.junit.Test;
+
+public class MetadataExportTest extends AbstractIntegrationTest {
+
+ private ItemService itemService = ContentServiceFactory.getInstance().getItemService();
+ private CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
+ private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
+ private WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
+ private InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
+ private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
+
+ @Test
+ public void metadataExportToCsvTest() throws Exception {
+ context.turnOffAuthorisationSystem();
+ Community community = communityService.create(null, context);
+ Collection collection = collectionService.create(context, community);
+ WorkspaceItem wi = workspaceItemService.create(context, collection, true);
+ Item item = wi.getItem();
+ itemService.addMetadata(context, item, "dc", "contributor", "author", null, "Donald, Smith");
+ item = installItemService.installItem(context, wi);
+ context.restoreAuthSystemState();
+ String fileLocation = configurationService.getProperty("dspace.dir") + testProps.get("test.exportcsv")
+ .toString();
+
+ String[] args = new String[] {"metadata-export", "-i", String.valueOf(item.getHandle()), "-f", fileLocation};
+ TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
+
+ ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
+ File file = new File(fileLocation);
+ String fileContent = IOUtils.toString(new FileInputStream(file), StandardCharsets.UTF_8);
+ assertTrue(fileContent.contains("Donald, Smith"));
+ assertTrue(fileContent.contains(String.valueOf(item.getID())));
+
+ context.turnOffAuthorisationSystem();
+ itemService.delete(context, itemService.find(context, item.getID()));
+ collectionService.delete(context, collectionService.find(context, collection.getID()));
+ communityService.delete(context, communityService.find(context, community.getID()));
+ context.restoreAuthSystemState();
+ }
+}
diff --git a/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataImportTest.java b/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataImportTest.java
new file mode 100644
index 0000000000..c0eb2789bc
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/app/bulkedit/MetadataImportTest.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.bulkedit;
+
+import static junit.framework.TestCase.assertTrue;
+
+import java.io.File;
+
+import org.apache.commons.lang3.StringUtils;
+import org.dspace.AbstractIntegrationTest;
+import org.dspace.app.launcher.ScriptLauncher;
+import org.dspace.app.scripts.handler.impl.TestDSpaceRunnableHandler;
+import org.dspace.content.Collection;
+import org.dspace.content.Community;
+import org.dspace.content.Item;
+import org.dspace.content.factory.ContentServiceFactory;
+import org.dspace.content.service.CollectionService;
+import org.dspace.content.service.CommunityService;
+import org.dspace.content.service.ItemService;
+import org.dspace.services.ConfigurationService;
+import org.dspace.services.factory.DSpaceServicesFactory;
+import org.junit.Test;
+
+public class MetadataImportTest extends AbstractIntegrationTest {
+
+ private ItemService itemService = ContentServiceFactory.getInstance().getItemService();
+ private CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
+ private CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
+ private ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
+
+ @Test
+ public void metadataImportTest() throws Exception {
+ context.turnOffAuthorisationSystem();
+ Community community = communityService.create(null, context);
+ Collection collection = collectionService.create(context, community);
+ context.restoreAuthSystemState();
+
+ String fileLocation = new File(testProps.get("test.importcsv").toString()).getAbsolutePath();
+ String[] args = new String[] {"metadata-import", "-f", fileLocation, "-e", eperson.getEmail(), "-s"};
+ TestDSpaceRunnableHandler testDSpaceRunnableHandler = new TestDSpaceRunnableHandler();
+
+ ScriptLauncher.handleScript(args, ScriptLauncher.getConfig(kernelImpl), testDSpaceRunnableHandler, kernelImpl);
+ Item importedItem = itemService.findAll(context).next();
+ assertTrue(
+ StringUtils.equals(
+ itemService.getMetadata(importedItem, "dc", "contributor", "author", Item.ANY).get(0).getValue(),
+ "Donald, SmithImported"));
+
+ context.turnOffAuthorisationSystem();
+ itemService.delete(context, itemService.find(context, importedItem.getID()));
+ collectionService.delete(context, collectionService.find(context, collection.getID()));
+ communityService.delete(context, communityService.find(context, community.getID()));
+ context.restoreAuthSystemState();
+ }
+}
diff --git a/dspace-api/src/test/java/org/dspace/app/scripts/handler/impl/TestDSpaceRunnableHandler.java b/dspace-api/src/test/java/org/dspace/app/scripts/handler/impl/TestDSpaceRunnableHandler.java
new file mode 100644
index 0000000000..1b5b3fa7ac
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/app/scripts/handler/impl/TestDSpaceRunnableHandler.java
@@ -0,0 +1,36 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.scripts.handler.impl;
+
+import org.dspace.scripts.handler.impl.CommandLineDSpaceRunnableHandler;
+
+/**
+ * This class will be used as a DSpaceRunnableHandler for the Tests so that we can stop the handler
+ * from calling System.exit() when a script would throw an exception
+ */
+public class TestDSpaceRunnableHandler extends CommandLineDSpaceRunnableHandler {
+
+ private Exception exception = null;
+
+ /**
+ * We're overriding this method so that we can stop the script from doing the System.exit() if
+ * an exception within the script is thrown
+ */
+ @Override
+ public void handleException(String message, Exception e) {
+ exception = e;
+ }
+
+ /**
+ * Generic getter for the exception
+ * @return the exception value of this TestDSpaceRunnableHandler
+ */
+ public Exception getException() {
+ return exception;
+ }
+}
diff --git a/dspace-api/src/test/java/org/dspace/license/MockCCLicenseConnectorServiceImpl.java b/dspace-api/src/test/java/org/dspace/license/MockCCLicenseConnectorServiceImpl.java
new file mode 100644
index 0000000000..bb443ab4a4
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/license/MockCCLicenseConnectorServiceImpl.java
@@ -0,0 +1,127 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.license;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jdom.Document;
+import org.jdom.JDOMException;
+
+/**
+ * Mock implementation for the Creative commons license connector service.
+ * This class will return a structure of CC Licenses similar to the CC License API but without having to contact it
+ */
+public class MockCCLicenseConnectorServiceImpl extends CCLicenseConnectorServiceImpl {
+
+ /**
+ * Retrieves mock CC Licenses for the provided language
+ * @param language - the language
+ * @return a map of mocked licenses with the id and the license
+ */
+ public Map retrieveLicenses(String language) {
+ Map ccLicenses = new HashMap<>();
+ CCLicense mockLicense1 = createMockLicense(1, new int[]{3, 2, 3});
+ CCLicense mockLicense2 = createMockLicense(2, new int[]{2});
+ CCLicense mockLicense3 = createMockLicense(3, new int[]{});
+
+ ccLicenses.put(mockLicense1.getLicenseId(), mockLicense1);
+ ccLicenses.put(mockLicense2.getLicenseId(), mockLicense2);
+ ccLicenses.put(mockLicense3.getLicenseId(), mockLicense3);
+
+ return ccLicenses;
+ }
+
+ private CCLicense createMockLicense(int count, int[] amountOfFieldsAndEnums) {
+ String licenseId = "license" + count;
+ String licenseName = "License " + count + " - Name";
+ List mockLicenseFields = createMockLicenseFields(count, amountOfFieldsAndEnums);
+ return new CCLicense(licenseId, licenseName, mockLicenseFields);
+ }
+
+ private List createMockLicenseFields(int count, int[] amountOfFieldsAndEnums) {
+ List ccLicenseFields = new LinkedList<>();
+ for (int index = 0; index < amountOfFieldsAndEnums.length; index++) {
+ String licenseFieldId = "license" + count + "-field" + index;
+ String licenseFieldLabel = "License " + count + " - Field " + index + " - Label";
+ String licenseFieldDescription = "License " + count + " - Field " + index + " - Description";
+ List mockLicenseFields = createMockLicenseFields(count,
+ index,
+ amountOfFieldsAndEnums[index]);
+ ccLicenseFields.add(new CCLicenseField(licenseFieldId,
+ licenseFieldLabel,
+ licenseFieldDescription,
+ mockLicenseFields));
+
+ }
+
+ return ccLicenseFields;
+ }
+
+ private List createMockLicenseFields(int count, int index, int amountOfEnums) {
+ List ccLicenseFieldEnumList = new LinkedList<>();
+ for (int i = 0; i < amountOfEnums; i++) {
+ String enumId = "license" + count + "-field" + index + "-enum" + i;
+ String enumLabel = "License " + count + " - Field " + index + " - Enum " + i + " - Label";
+ String enumDescription = "License " + count + " - Field " + index + " - Enum " + i + " - " +
+ "Description";
+ ccLicenseFieldEnumList.add(new CCLicenseFieldEnum(enumId, enumLabel, enumDescription));
+ }
+ return ccLicenseFieldEnumList;
+
+ }
+
+ /**
+ * Retrieve a mock CC License URI
+ *
+ * @param licenseId - the ID of the license
+ * @param language - the language for which to retrieve the full answerMap
+ * @param answerMap - the answers to the different field questions
+ * @return the CC License URI
+ */
+ public String retrieveRightsByQuestion(final String licenseId,
+ final String language,
+ final Map answerMap) {
+
+ return "mock-license-uri";
+ }
+
+ /**
+ * Retrieve a mock license RDF document.
+ * When the uri contains "invalid", null will be returned to simulate that no document was found for the provided
+ * URI
+ *
+ * @param licenseURI - The license URI for which to retrieve the license RDF document
+ * @return a mock license RDF document or null when the URI contains invalid
+ * @throws IOException
+ */
+ public Document retrieveLicenseRDFDoc(String licenseURI) throws IOException {
+ if (!StringUtils.contains(licenseURI, "invalid")) {
+ InputStream cclicense = null;
+ try {
+ cclicense = getClass().getResourceAsStream("cc-license-rdf.xml");
+
+ Document doc = parser.build(cclicense);
+ return doc;
+ } catch (JDOMException e) {
+ throw new RuntimeException(e);
+ } finally {
+ if (cclicense != null) {
+ cclicense.close();
+ }
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/dspace-api/src/test/java/org/dspace/scripts/MockDSpaceRunnableScriptConfiguration.java b/dspace-api/src/test/java/org/dspace/scripts/MockDSpaceRunnableScriptConfiguration.java
new file mode 100644
index 0000000000..1197370e32
--- /dev/null
+++ b/dspace-api/src/test/java/org/dspace/scripts/MockDSpaceRunnableScriptConfiguration.java
@@ -0,0 +1,68 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.scripts;
+
+import java.io.InputStream;
+import java.sql.SQLException;
+
+import org.apache.commons.cli.Options;
+import org.dspace.authorize.service.AuthorizeService;
+import org.dspace.core.Context;
+import org.dspace.scripts.configuration.ScriptConfiguration;
+import org.dspace.scripts.impl.MockDSpaceRunnableScript;
+import org.springframework.beans.factory.annotation.Autowired;
+
+public class MockDSpaceRunnableScriptConfiguration extends ScriptConfiguration {
+
+
+ @Autowired
+ private AuthorizeService authorizeService;
+
+ private Class dspaceRunnableClass;
+
+ @Override
+ public Class getDspaceRunnableClass() {
+ return dspaceRunnableClass;
+ }
+
+ /**
+ * Generic setter for the dspaceRunnableClass
+ * @param dspaceRunnableClass The dspaceRunnableClass to be set on this MetadataExportScriptConfiguration
+ */
+ @Override
+ public void setDspaceRunnableClass(Class dspaceRunnableClass) {
+ this.dspaceRunnableClass = dspaceRunnableClass;
+ }
+
+ @Override
+ public boolean isAllowedToExecute(Context context) {
+ try {
+ return authorizeService.isAdmin(context);
+ } catch (SQLException e) {
+ throw new RuntimeException("SQLException occurred when checking if the current user is an admin", e);
+ }
+ }
+
+ @Override
+ public Options getOptions() {
+ if (options == null) {
+ Options options = new Options();
+
+ options.addOption("r", "remove", true, "description r");
+ options.getOption("r").setType(String.class);
+ options.addOption("i", "index", false, "description i");
+ options.getOption("i").setType(boolean.class);
+ options.getOption("i").setRequired(true);
+ options.addOption("f", "file", true, "source file");
+ options.getOption("f").setType(InputStream.class);
+ options.getOption("f").setRequired(false);
+ super.options = options;
+ }
+ return options;
+ }
+}
diff --git a/dspace-api/src/test/java/org/dspace/scripts/impl/MockDSpaceRunnableScript.java b/dspace-api/src/test/java/org/dspace/scripts/impl/MockDSpaceRunnableScript.java
index 75f723d64b..960927e90a 100644
--- a/dspace-api/src/test/java/org/dspace/scripts/impl/MockDSpaceRunnableScript.java
+++ b/dspace-api/src/test/java/org/dspace/scripts/impl/MockDSpaceRunnableScript.java
@@ -7,19 +7,20 @@
*/
package org.dspace.scripts.impl;
-import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.dspace.scripts.DSpaceRunnable;
+import org.dspace.scripts.MockDSpaceRunnableScriptConfiguration;
+import org.dspace.utils.DSpace;
-public class MockDSpaceRunnableScript extends DSpaceRunnable {
-
- private MockDSpaceRunnableScript() {
- Options options = constructOptions();
- this.options = options;
+public class MockDSpaceRunnableScript extends DSpaceRunnable {
+ @Override
+ public void internalRun() throws Exception {
}
@Override
- public void internalRun() throws Exception {
+ public MockDSpaceRunnableScriptConfiguration getScriptConfiguration() {
+ return new DSpace().getServiceManager()
+ .getServiceByName("mock-script", MockDSpaceRunnableScriptConfiguration.class);
}
@Override
@@ -28,15 +29,4 @@ public class MockDSpaceRunnableScript extends DSpaceRunnable {
throw new ParseException("-i is a mandatory parameter");
}
}
-
- private Options constructOptions() {
- Options options = new Options();
-
- options.addOption("r", "remove", true, "description r");
- options.getOption("r").setType(String.class);
- options.addOption("i", "index", true, "description i");
- options.getOption("i").setType(boolean.class);
- options.getOption("i").setRequired(true);
- return options;
- }
}
diff --git a/dspace-api/src/test/resources/test-config.properties b/dspace-api/src/test/resources/test-config.properties
index 49aaa9bb10..66a29ab9a0 100644
--- a/dspace-api/src/test/resources/test-config.properties
+++ b/dspace-api/src/test/resources/test-config.properties
@@ -11,3 +11,5 @@ test.folder = ./target/testing/
# Path of the test bitstream (to use in BitstreamTest and elsewhere)
test.bitstream = ./target/testing/dspace/assetstore/ConstitutionofIreland.pdf
+test.exportcsv = ./target/testing/dspace/assetstore/test.csv
+test.importcsv = ./target/testing/dspace/assetstore/testImport.csv
diff --git a/dspace-rest/pom.xml b/dspace-rest/pom.xml
index 8f69306085..1038617b49 100644
--- a/dspace-rest/pom.xml
+++ b/dspace-rest/pom.xml
@@ -19,7 +19,7 @@
${basedir}/..
- 5.3.1.RELEASE
+ 5.3.3.RELEASE
diff --git a/dspace-server-webapp/pom.xml b/dspace-server-webapp/pom.xml
index 88e31751f3..d8cc6a7587 100644
--- a/dspace-server-webapp/pom.xml
+++ b/dspace-server-webapp/pom.xml
@@ -172,6 +172,21 @@
+
+
+ com.mycila
+ license-maven-plugin
+
+
+ **/src/test/resources/**
+ **/src/test/data/**
+
+ src/main/webapp/index.html
+ src/main/webapp/login.html
+ src/main/webapp/js/hal/**
+
+
+
@@ -242,6 +257,23 @@
${spring-hal-browser.version}
+
+
+
+ org.webjars.bowergithub.jquery
+ jquery-dist
+ 3.5.1
+
+
+
+ org.webjars.bowergithub.codeseven
+ toastr
+ 2.1.4
+
+
+
org.springframework.boot
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/Application.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/Application.java
index c89dd77f4f..18d06c87e8 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/Application.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/Application.java
@@ -32,6 +32,7 @@ import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
@@ -149,6 +150,18 @@ public class Application extends SpringBootServletInitializer {
}
}
+ /**
+ * Add a new ResourceHandler to allow us to use WebJars.org to pull in web dependencies
+ * dynamically for HAL Browser, and access them off the /webjars path.
+ * @param registry ResourceHandlerRegistry
+ */
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ registry
+ .addResourceHandler("/webjars/**")
+ .addResourceLocations("/webjars/");
+ }
+
@Override
public void addArgumentResolvers(@NonNull List argumentResolvers) {
argumentResolvers.add(new SearchFilterResolver());
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/RelationshipTypeRestController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/RelationshipTypeRestController.java
index 31d427254a..46aefbe69e 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/RelationshipTypeRestController.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/RelationshipTypeRestController.java
@@ -81,7 +81,7 @@ public class RelationshipTypeRestController {
List list = relationshipTypeService.findByEntityType(context, entityType, -1, -1);
Page relationshipTypeRestPage = converter
- .toRestPage(list, pageable, list.size(), utils.obtainProjection());
+ .toRestPage(list, pageable, utils.obtainProjection());
Page relationshipTypeResources = relationshipTypeRestPage
.map(relationshipTypeRest -> new RelationshipTypeResource(relationshipTypeRest, utils));
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/RestResourceController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/RestResourceController.java
index a1684d782e..b501ba4406 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/RestResourceController.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/RestResourceController.java
@@ -342,7 +342,15 @@ public class RestResourceController implements InitializingBean {
return findRelEntryInternal(request, response, apiCategory, model, id, rel, relid, page, assembler);
}
-
+ @RequestMapping(method = RequestMethod.GET, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT +
+ "/{rel}/{relid}")
+ public RepresentationModel findRel(HttpServletRequest request, HttpServletResponse response,
+ @PathVariable String apiCategory,
+ @PathVariable String model, @PathVariable Integer id, @PathVariable String rel,
+ @PathVariable String relid,
+ Pageable page, PagedResourcesAssembler assembler) throws Throwable {
+ return findRelEntryInternal(request, response, apiCategory, model, id.toString(), rel, relid, page, assembler);
+ }
/**
* Execute a POST request;
*
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ScriptProcessesController.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ScriptProcessesController.java
index 122fa76ac0..5cc956c5b1 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/ScriptProcessesController.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/ScriptProcessesController.java
@@ -7,6 +7,8 @@
*/
package org.dspace.app.rest;
+import java.util.List;
+
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.app.rest.converter.ConverterService;
@@ -14,6 +16,9 @@ import org.dspace.app.rest.model.ProcessRest;
import org.dspace.app.rest.model.ScriptRest;
import org.dspace.app.rest.model.hateoas.ProcessResource;
import org.dspace.app.rest.repository.ScriptRestRepository;
+import org.dspace.app.rest.utils.ContextUtil;
+import org.dspace.core.Context;
+import org.dspace.services.RequestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.rest.webmvc.ControllerUtils;
import org.springframework.hateoas.RepresentationModel;
@@ -24,7 +29,9 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
/**
* This controller adds additional subresource methods to allow connecting scripts with processes
@@ -41,6 +48,9 @@ public class ScriptProcessesController {
@Autowired
private ScriptRestRepository scriptRestRepository;
+ @Autowired
+ private RequestService requestService;
+
/**
* This method can be called by sending a POST request to the system/scripts/{name}/processes endpoint
* This will start a process for the script that matches the given name
@@ -50,13 +60,16 @@ public class ScriptProcessesController {
*/
@RequestMapping(method = RequestMethod.POST)
@PreAuthorize("hasAuthority('ADMIN')")
- public ResponseEntity> startProcess(@PathVariable(name = "name") String scriptName)
+ public ResponseEntity> startProcess(@PathVariable(name = "name") String scriptName,
+ @RequestParam(name = "file") List files)
throws Exception {
if (log.isTraceEnabled()) {
log.trace("Starting Process for Script with name: " + scriptName);
}
- ProcessRest processRest = scriptRestRepository.startProcess(scriptName);
+ Context context = ContextUtil.obtainContext(requestService.getCurrentRequest().getServletRequest());
+ ProcessRest processRest = scriptRestRepository.startProcess(context, scriptName, files);
ProcessResource processResource = converter.toResource(processRest);
+ context.complete();
return ControllerUtils.toResponseEntity(HttpStatus.ACCEPTED, new HttpHeaders(), processResource);
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/SubmissionCCLicenseUrlRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/SubmissionCCLicenseUrlRepository.java
new file mode 100644
index 0000000000..957484319c
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/SubmissionCCLicenseUrlRepository.java
@@ -0,0 +1,140 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.ServletRequest;
+
+import org.apache.commons.lang3.StringUtils;
+import org.dspace.app.rest.converter.ConverterService;
+import org.dspace.app.rest.exception.DSpaceBadRequestException;
+import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
+import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
+import org.dspace.app.rest.model.wrapper.SubmissionCCLicenseUrl;
+import org.dspace.app.rest.repository.DSpaceRestRepository;
+import org.dspace.app.rest.utils.Utils;
+import org.dspace.core.Context;
+import org.dspace.license.service.CreativeCommonsService;
+import org.dspace.services.RequestService;
+import org.dspace.utils.DSpace;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.hateoas.Link;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+/**
+ * This Repository is responsible for handling the CC License URIs.
+ * It only supports a search method
+ */
+
+@Component(SubmissionCCLicenseUrlRest.CATEGORY + "." + SubmissionCCLicenseUrlRest.NAME)
+public class SubmissionCCLicenseUrlRepository extends DSpaceRestRepository
+ implements InitializingBean {
+
+ @Autowired
+ protected Utils utils;
+
+ @Autowired
+ protected CreativeCommonsService creativeCommonsService;
+
+ @Autowired
+ protected ConverterService converter;
+
+ protected RequestService requestService = new DSpace().getRequestService();
+
+ @Autowired
+ DiscoverableEndpointsService discoverableEndpointsService;
+
+ /**
+ * Retrieves the CC License URI based on the license ID and answers in the field questions, provided as parameters
+ * to this request
+ *
+ * @return the CC License URI as a SubmissionCCLicenseUrlRest
+ */
+ @PreAuthorize("hasAuthority('AUTHENTICATED')")
+ @SearchRestMethod(name = "rightsByQuestions")
+ public SubmissionCCLicenseUrlRest findByRightsByQuestions() {
+ ServletRequest servletRequest = requestService.getCurrentRequest()
+ .getServletRequest();
+ Map requestParameterMap = servletRequest
+ .getParameterMap();
+ Map parameterMap = new HashMap<>();
+ String licenseId = servletRequest.getParameter("license");
+ if (StringUtils.isBlank(licenseId)) {
+ throw new DSpaceBadRequestException(
+ "A \"license\" parameter needs to be provided.");
+ }
+
+ // Loop through parameters to find answer parameters, adding them to the parameterMap. Zero or more answers
+ // may exist, as some CC licenses do not require answers
+ for (String parameter : requestParameterMap.keySet()) {
+ if (StringUtils.startsWith(parameter, "answer_")) {
+ String field = StringUtils.substringAfter(parameter, "answer_");
+ String answer = "";
+ if (requestParameterMap.get(parameter).length > 0) {
+ answer = requestParameterMap.get(parameter)[0];
+ }
+ parameterMap.put(field, answer);
+ }
+ }
+
+ Map fullParamMap = creativeCommonsService.retrieveFullAnswerMap(licenseId, parameterMap);
+ if (fullParamMap == null) {
+ throw new ResourceNotFoundException("No CC License could be matched on the provided ID: " + licenseId);
+ }
+ boolean licenseContainsCorrectInfo = creativeCommonsService.verifyLicenseInformation(licenseId, fullParamMap);
+ if (!licenseContainsCorrectInfo) {
+ throw new DSpaceBadRequestException(
+ "The provided answers do not match the required fields for the provided license.");
+ }
+
+ String licenseUri = creativeCommonsService.retrieveLicenseUri(licenseId, fullParamMap);
+
+ SubmissionCCLicenseUrl submissionCCLicenseUrl = new SubmissionCCLicenseUrl(licenseUri, licenseUri);
+ if (StringUtils.isBlank(licenseUri)) {
+ throw new ResourceNotFoundException("No CC License URI could be found for ID: " + licenseId);
+ }
+
+ return converter.toRest(submissionCCLicenseUrl, utils.obtainProjection());
+
+ }
+
+ /**
+ * The findOne method is not supported in this repository
+ */
+ @PreAuthorize("permitAll()")
+ public SubmissionCCLicenseUrlRest findOne(final Context context, final String s) {
+ throw new RepositoryMethodNotImplementedException(SubmissionCCLicenseUrlRest.NAME, "findOne");
+ }
+
+ /**
+ * The findAll method is not supported in this repository
+ */
+ public Page findAll(final Context context, final Pageable pageable) {
+ throw new RepositoryMethodNotImplementedException(SubmissionCCLicenseUrlRest.NAME, "findAll");
+ }
+
+ public Class getDomainClass() {
+ return SubmissionCCLicenseUrlRest.class;
+ }
+
+ @Override
+ public void afterPropertiesSet() {
+ discoverableEndpointsService.register(this, Arrays.asList(
+ new Link("/api/" + SubmissionCCLicenseUrlRest.CATEGORY + "/" +
+ SubmissionCCLicenseUrlRest.NAME + "/search",
+ SubmissionCCLicenseUrlRest.NAME + "-search")));
+ }
+
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowDefinitionCollectionsLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowDefinitionCollectionsLinkRepository.java
index 1f66c0928d..7ae5f5ecc0 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowDefinitionCollectionsLinkRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowDefinitionCollectionsLinkRepository.java
@@ -72,7 +72,7 @@ public class WorkflowDefinitionCollectionsLinkRepository extends AbstractDSpaceR
collectionsMappedToWorkflow.addAll(xmlWorkflowFactory.getCollectionHandlesMappedToWorklow(context,
workflowName));
Pageable pageable = optionalPageable != null ? optionalPageable : PageRequest.of(0, 20);
- return converter.toRestPage(utils.getPage(collectionsMappedToWorkflow, pageable),
+ return converter.toRestPage(collectionsMappedToWorkflow, pageable,
projection);
} else {
throw new ResourceNotFoundException("No workflow with name " + workflowName + " is configured");
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowDefinitionStepsLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowDefinitionStepsLinkRepository.java
index 4fdc391641..24c82ee460 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowDefinitionStepsLinkRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowDefinitionStepsLinkRepository.java
@@ -55,7 +55,7 @@ public class WorkflowDefinitionStepsLinkRepository extends AbstractDSpaceRestRep
try {
List steps = xmlWorkflowFactory.getWorkflowByName(workflowName).getSteps();
Pageable pageable = optionalPageable != null ? optionalPageable : PageRequest.of(0, 20);
- return converter.toRestPage(utils.getPage(steps, pageable), projection);
+ return converter.toRestPage(steps, pageable, projection);
} catch (WorkflowConfigurationException e) {
throw new ResourceNotFoundException("No workflow with name " + workflowName + " is configured");
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowStepActionsLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowStepActionsLinkRepository.java
index 8ddab1381f..f2b6a423f8 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowStepActionsLinkRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/WorkflowStepActionsLinkRepository.java
@@ -52,6 +52,6 @@ public class WorkflowStepActionsLinkRepository extends AbstractDSpaceRestReposit
Projection projection) {
List actions = xmlWorkflowFactory.getStepByName(workflowStepName).getActions();
Pageable pageable = optionalPageable != null ? optionalPageable : PageRequest.of(0, 20);
- return converter.toRestPage(utils.getPage(actions, pageable), projection);
+ return converter.toRestPage(actions, pageable, projection);
}
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ConverterService.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ConverterService.java
index a9dc827b79..fc786bfc85 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ConverterService.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ConverterService.java
@@ -7,33 +7,44 @@
*/
package org.dspace.app.rest.converter;
+import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.HashMap;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
+import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.dspace.app.rest.link.HalLinkFactory;
import org.dspace.app.rest.link.HalLinkService;
+import org.dspace.app.rest.model.BaseObjectRest;
import org.dspace.app.rest.model.RestAddressableModel;
import org.dspace.app.rest.model.RestModel;
import org.dspace.app.rest.model.hateoas.HALResource;
import org.dspace.app.rest.projection.DefaultProjection;
import org.dspace.app.rest.projection.Projection;
+import org.dspace.app.rest.repository.DSpaceRestRepository;
+import org.dspace.app.rest.security.DSpacePermissionEvaluator;
+import org.dspace.app.rest.security.WebSecurityExpressionEvaluator;
import org.dspace.app.rest.utils.Utils;
+import org.dspace.services.RequestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
+import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@@ -64,6 +75,15 @@ public class ConverterService {
@Autowired
private List projections;
+ @Autowired
+ private DSpacePermissionEvaluator dSpacePermissionEvaluator;
+
+ @Autowired
+ private WebSecurityExpressionEvaluator webSecurityExpressionEvaluator;
+
+ @Autowired
+ private RequestService requestService;
+
/**
* Converts the given model object to a rest object, using the appropriate {@link DSpaceConverter} and
* the given projection.
@@ -86,18 +106,74 @@ public class ConverterService {
M transformedModel = projection.transformModel(modelObject);
DSpaceConverter converter = requireConverter(modelObject.getClass());
R restObject = converter.convert(transformedModel, projection);
+ if (restObject instanceof BaseObjectRest) {
+ BaseObjectRest baseObjectRest = (BaseObjectRest) restObject;
+ // This section will verify whether the current user has permissions to retrieve the
+ // rest object. It'll only return the REST object if the permission is granted.
+ // If permission isn't granted, it'll return null
+ String preAuthorizeValue = getPreAuthorizeAnnotationForBaseObject(baseObjectRest);
+ if (!webSecurityExpressionEvaluator
+ .evaluate(preAuthorizeValue, requestService.getCurrentRequest().getHttpServletRequest(),
+ requestService.getCurrentRequest().getHttpServletResponse(),
+ String.valueOf(baseObjectRest.getId()))) {
+ log.debug("Access denied on " + restObject.getClass() + " with id: " +
+ ((BaseObjectRest) restObject).getId());
+ return null;
+ }
+ }
if (restObject instanceof RestModel) {
return (R) projection.transformRest((RestModel) restObject);
}
return restObject;
}
+ private String getPreAuthorizeAnnotationForBaseObject(BaseObjectRest restObject) {
+ Annotation preAuthorize = getAnnotationForRestObject(restObject);
+ if (preAuthorize == null) {
+ preAuthorize = getDefaultFindOnePreAuthorize();
+
+ }
+ return parseAnnotation(preAuthorize);
+
+ }
+
+ private String parseAnnotation(Annotation preAuthorize) {
+ if (preAuthorize != null) {
+ return (String) AnnotationUtils.getValue(preAuthorize);
+ }
+ return null;
+ }
+
+ private Annotation getAnnotationForRestObject(BaseObjectRest restObject) {
+ BaseObjectRest baseObjectRest = restObject;
+ DSpaceRestRepository repositoryToUse = utils
+ .getResourceRepositoryByCategoryAndModel(baseObjectRest.getCategory(), baseObjectRest.getType());
+ Annotation preAuthorize = null;
+ for (Method m : repositoryToUse.getClass().getMethods()) {
+ if (StringUtils.equalsIgnoreCase(m.getName(), "findOne")) {
+ preAuthorize = AnnotationUtils.findAnnotation(m, PreAuthorize.class);
+ }
+ }
+ return preAuthorize;
+ }
+
+ private Annotation getDefaultFindOnePreAuthorize() {
+ for (Method m : DSpaceRestRepository.class.getMethods()) {
+ if (StringUtils.equalsIgnoreCase(m.getName(), "findOne")) {
+ Annotation annotation = AnnotationUtils.findAnnotation(m, PreAuthorize.class);
+ if (annotation != null) {
+ return annotation;
+ }
+ }
+ }
+ return null;
+ }
+
/**
* Converts a list of model objects to a page of rest objects using the given {@link Projection}.
*
* @param modelObjects the list of model objects.
* @param pageable the pageable.
- * @param total the total number of items.
* @param projection the projection to use.
* @param the model object class.
* @param the rest object class.
@@ -105,25 +181,48 @@ public class ConverterService {
* @throws IllegalArgumentException if there is no compatible converter.
* @throws ClassCastException if the converter's return type is not compatible with the inferred return type.
*/
- public Page toRestPage(List modelObjects, Pageable pageable, long total, Projection projection) {
- return new PageImpl<>(modelObjects, pageable, total).map((object) -> toRest(object, projection));
+ public Page toRestPage(List modelObjects, Pageable pageable, Projection projection) {
+ List transformedList = new LinkedList<>();
+ for (M modelObject : modelObjects) {
+ R transformedObject = toRest(modelObject, projection);
+ if (transformedObject != null) {
+ transformedList.add(transformedObject);
+ }
+ }
+ if (pageable == null) {
+ pageable = utils.getPageable(pageable);
+ }
+ return utils.getPage(transformedList, pageable);
}
/**
- * Converts a list of model objects to a page of rest objects using the given {@link Projection}.
- *
- * @param modelObjects the page of model objects.
+ * Converts a list of ModelObjects to a page of Rest Objects using the given {@link Projection}
+ * This method differences in the sense that we define a total here instead of the size of the list because
+ * this method will be called if the list is limited through a DB call already and thus we need to give the
+ * total amount of records in the DB; not the size of the given list
+ * @param modelObjects the list of model objects.
+ * @param pageable the pageable.
+ * @param total The total amount of objects
* @param projection the projection to use.
* @param the model object class.
* @param the rest object class.
* @return the page.
- * @throws IllegalArgumentException if there is no compatible converter.
- * @throws ClassCastException if the converter's return type is not compatible with the inferred return type.
*/
- public Page toRestPage(Page modelObjects, Projection projection) {
- return modelObjects.map((object) -> toRest(object, projection));
+ public Page toRestPage(List modelObjects, Pageable pageable, long total, Projection projection) {
+ List transformedList = new LinkedList<>();
+ for (M modelObject : modelObjects) {
+ R transformedObject = toRest(modelObject, projection);
+ if (transformedObject != null) {
+ transformedList.add(transformedObject);
+ }
+ }
+ if (pageable == null) {
+ pageable = utils.getPageable(pageable);
+ }
+ return new PageImpl(transformedList, pageable, total);
}
+
/**
* Gets the converter supporting the given class as input.
*
@@ -177,6 +276,9 @@ public class ConverterService {
* @return the fully converted resource, with all automatic links and embeds applied.
*/
public T toResource(RestModel restObject, Link... oldLinks) {
+ if (restObject == null) {
+ return null;
+ }
T halResource = getResource(restObject);
if (restObject instanceof RestAddressableModel) {
utils.embedOrLinkClassLevelRels(halResource, oldLinks);
@@ -288,19 +390,19 @@ public class ConverterService {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(EntityModel.class));
Set beanDefinitions = provider.findCandidateComponents(
- HALResource.class.getPackage().getName().replaceAll("\\.", "/"));
+ HALResource.class.getPackage().getName().replaceAll("\\.", "/"));
for (BeanDefinition beanDefinition : beanDefinitions) {
String resourceClassName = beanDefinition.getBeanClassName();
String resourceClassSimpleName = resourceClassName.substring(resourceClassName.lastIndexOf(".") + 1);
String restClassSimpleName = resourceClassSimpleName
- .replaceAll("ResourceWrapper$", "RestWrapper")
- .replaceAll("Resource$", "Rest");
+ .replaceAll("ResourceWrapper$", "RestWrapper")
+ .replaceAll("Resource$", "Rest");
String restClassName = RestModel.class.getPackage().getName() + "." + restClassSimpleName;
try {
Class extends RestModel> restClass =
- (Class extends RestModel>) Class.forName(restClassName);
+ (Class extends RestModel>) Class.forName(restClassName);
Class> resourceClass =
- (Class>) Class.forName(resourceClassName);
+ (Class>) Class.forName(resourceClassName);
Constructor compatibleConstructor = null;
for (Constructor constructor : resourceClass.getDeclaredConstructors()) {
if (constructor.getParameterCount() == 2 && constructor.getParameterTypes()[1] == Utils.class) {
@@ -314,11 +416,11 @@ public class ConverterService {
resourceConstructors.put(restClass, compatibleConstructor);
} else {
log.warn("Skipping registration of resource class " + resourceClassName
- + "; compatible constructor not found");
+ + "; compatible constructor not found");
}
} catch (ClassNotFoundException e) {
log.warn("Skipping registration of resource class " + resourceClassName
- + "; rest class not found: " + restClassName);
+ + "; rest class not found: " + restClassName);
}
}
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/RootConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/RootConverter.java
index b75f5f2751..c49d19842d 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/RootConverter.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/RootConverter.java
@@ -24,8 +24,8 @@ public class RootConverter {
public RootRest convert() {
RootRest rootRest = new RootRest();
rootRest.setDspaceName(configurationService.getProperty("dspace.name"));
- rootRest.setDspaceURL(configurationService.getProperty("dspace.ui.url"));
- rootRest.setDspaceRest(configurationService.getProperty("dspace.server.url"));
+ rootRest.setDspaceUI(configurationService.getProperty("dspace.ui.url"));
+ rootRest.setDspaceServer(configurationService.getProperty("dspace.server.url"));
return rootRest;
}
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ScriptConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ScriptConverter.java
index 379d651617..105975355b 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ScriptConverter.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/ScriptConverter.java
@@ -15,7 +15,7 @@ import org.apache.commons.collections4.CollectionUtils;
import org.dspace.app.rest.model.ParameterRest;
import org.dspace.app.rest.model.ScriptRest;
import org.dspace.app.rest.projection.Projection;
-import org.dspace.scripts.DSpaceRunnable;
+import org.dspace.scripts.configuration.ScriptConfiguration;
import org.springframework.stereotype.Component;
/**
@@ -23,18 +23,18 @@ import org.springframework.stereotype.Component;
* of {@link ScriptRest}
*/
@Component
-public class ScriptConverter implements DSpaceConverter {
+public class ScriptConverter implements DSpaceConverter {
@Override
- public ScriptRest convert(DSpaceRunnable script, Projection projection) {
+ public ScriptRest convert(ScriptConfiguration scriptConfiguration, Projection projection) {
ScriptRest scriptRest = new ScriptRest();
scriptRest.setProjection(projection);
- scriptRest.setDescription(script.getDescription());
- scriptRest.setId(script.getName());
- scriptRest.setName(script.getName());
+ scriptRest.setDescription(scriptConfiguration.getDescription());
+ scriptRest.setId(scriptConfiguration.getName());
+ scriptRest.setName(scriptConfiguration.getName());
List parameterRestList = new LinkedList<>();
- for (Option option : CollectionUtils.emptyIfNull(script.getOptions().getOptions())) {
+ for (Option option : CollectionUtils.emptyIfNull(scriptConfiguration.getOptions().getOptions())) {
ParameterRest parameterRest = new ParameterRest();
parameterRest.setDescription(option.getDescription());
parameterRest.setName((option.getOpt() != null ? "-" + option.getOpt() : "--" + option.getLongOpt()));
@@ -49,7 +49,7 @@ public class ScriptConverter implements DSpaceConverter getModelClass() {
- return DSpaceRunnable.class;
+ public Class getModelClass() {
+ return ScriptConfiguration.class;
}
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseConverter.java
new file mode 100644
index 0000000000..bf6b92a618
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseConverter.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.converter;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.dspace.app.rest.model.SubmissionCCLicenseFieldRest;
+import org.dspace.app.rest.model.SubmissionCCLicenseRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.license.CCLicense;
+import org.dspace.license.CCLicenseField;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * This converter is responsible for transforming the model representation of an CCLicense to the REST
+ * representation of an CCLicense and vice versa
+ **/
+@Component
+public class SubmissionCCLicenseConverter implements DSpaceConverter {
+
+ @Autowired
+ private ConverterService converter;
+
+ /**
+ * Convert a CCLicense to its REST representation
+ * @param modelObject - the CCLicense to convert
+ * @param projection - the projection
+ * @return the corresponding SubmissionCCLicenseRest object
+ */
+ @Override
+ public SubmissionCCLicenseRest convert(final CCLicense modelObject, final Projection projection) {
+ SubmissionCCLicenseRest submissionCCLicenseRest = new SubmissionCCLicenseRest();
+ submissionCCLicenseRest.setProjection(projection);
+ submissionCCLicenseRest.setId(modelObject.getLicenseId());
+ submissionCCLicenseRest.setName(modelObject.getLicenseName());
+
+ List ccLicenseFieldList = modelObject.getCcLicenseFieldList();
+ List submissionCCLicenseFieldRests = new LinkedList<>();
+ if (ccLicenseFieldList != null) {
+ for (CCLicenseField ccLicenseField : ccLicenseFieldList) {
+ submissionCCLicenseFieldRests.add(converter.toRest(ccLicenseField, projection));
+ }
+ }
+ submissionCCLicenseRest.setFields(submissionCCLicenseFieldRests);
+ return submissionCCLicenseRest;
+ }
+
+ @Override
+ public Class getModelClass() {
+ return CCLicense.class;
+ }
+
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseFieldConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseFieldConverter.java
new file mode 100644
index 0000000000..782056dc1c
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseFieldConverter.java
@@ -0,0 +1,62 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.converter;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.dspace.app.rest.model.SubmissionCCLicenseFieldEnumRest;
+import org.dspace.app.rest.model.SubmissionCCLicenseFieldRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.license.CCLicenseField;
+import org.dspace.license.CCLicenseFieldEnum;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * This converter is responsible for transforming the model representation of an CCLicenseField to the REST
+ * representation of an CCLicenseField and vice versa
+ * The CCLicenseField is a sub component of the CCLicense object
+ **/
+@Component
+public class SubmissionCCLicenseFieldConverter
+ implements DSpaceConverter {
+
+ @Autowired
+ private ConverterService converter;
+
+ /**
+ * Convert a CCLicenseField to its REST representation
+ * @param modelObject - the CCLicenseField to convert
+ * @param projection - the projection
+ * @return the corresponding SubmissionCCLicenseFieldRest object
+ */
+ @Override
+ public SubmissionCCLicenseFieldRest convert(final CCLicenseField modelObject, final Projection projection) {
+ SubmissionCCLicenseFieldRest submissionCCLicenseFieldRest = new SubmissionCCLicenseFieldRest();
+ submissionCCLicenseFieldRest.setId(modelObject.getId());
+ submissionCCLicenseFieldRest.setLabel(modelObject.getLabel());
+ submissionCCLicenseFieldRest.setDescription(modelObject.getDescription());
+
+ List fieldEnum = modelObject.getFieldEnum();
+ List submissionCCLicenseFieldEnumRests = new LinkedList<>();
+ if (fieldEnum != null) {
+ for (CCLicenseFieldEnum ccLicenseFieldEnum : fieldEnum) {
+ submissionCCLicenseFieldEnumRests.add(converter.toRest(ccLicenseFieldEnum, projection));
+ }
+ }
+ submissionCCLicenseFieldRest.setEnums(submissionCCLicenseFieldEnumRests);
+ return submissionCCLicenseFieldRest;
+ }
+
+ @Override
+ public Class getModelClass() {
+ return CCLicenseField.class;
+ }
+
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseFieldEnumConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseFieldEnumConverter.java
new file mode 100644
index 0000000000..6c8993905f
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseFieldEnumConverter.java
@@ -0,0 +1,46 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.converter;
+
+import org.dspace.app.rest.model.SubmissionCCLicenseFieldEnumRest;
+import org.dspace.app.rest.projection.Projection;
+import org.dspace.license.CCLicenseFieldEnum;
+import org.springframework.stereotype.Component;
+
+/**
+ * This converter is responsible for transforming the model representation of an CCLicenseFieldEnum to the REST
+ * representation of an CCLicenseFieldEnum and vice versa
+ * The CCLicenseFieldEnum is a sub component of the CCLicenseField object
+ **/
+@Component
+public class SubmissionCCLicenseFieldEnumConverter
+ implements DSpaceConverter {
+
+ /**
+ * Convert a CCLicenseFieldEnum to its REST representation
+ *
+ * @param modelObject - the CCLicenseField to convert
+ * @param projection - the projection
+ * @return the corresponding SubmissionCCLicenseFieldEnumRest object
+ */
+ @Override
+ public SubmissionCCLicenseFieldEnumRest convert(final CCLicenseFieldEnum modelObject, final Projection projection) {
+ SubmissionCCLicenseFieldEnumRest submissionCCLicenseFieldEnumRest = new SubmissionCCLicenseFieldEnumRest();
+ submissionCCLicenseFieldEnumRest.setId(modelObject.getId());
+ submissionCCLicenseFieldEnumRest.setLabel(modelObject.getLabel());
+ submissionCCLicenseFieldEnumRest.setDescription(modelObject.getDescription());
+
+ return submissionCCLicenseFieldEnumRest;
+ }
+
+ @Override
+ public Class getModelClass() {
+ return CCLicenseFieldEnum.class;
+ }
+
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseUrlConverter.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseUrlConverter.java
new file mode 100644
index 0000000000..c5fd41fb7b
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/converter/SubmissionCCLicenseUrlConverter.java
@@ -0,0 +1,44 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.converter;
+
+import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
+import org.dspace.app.rest.model.wrapper.SubmissionCCLicenseUrl;
+import org.dspace.app.rest.projection.Projection;
+import org.springframework.stereotype.Component;
+
+
+/**
+ * This converter is responsible for transforming a Submission CC License Url String to the REST
+ * representation SubmissionCCLicenseUrlRest and vice versa
+ */
+@Component
+public class SubmissionCCLicenseUrlConverter
+ implements DSpaceConverter {
+
+ /**
+ * Convert a Submission CC License Url String to its REST representation
+ * @param modelObject - the CC License Url object to convert
+ * @param projection - the projection
+ * @return the corresponding SubmissionCCLicenseUrlRest object
+ */
+ @Override
+ public SubmissionCCLicenseUrlRest convert(SubmissionCCLicenseUrl modelObject, Projection projection) {
+ SubmissionCCLicenseUrlRest submissionCCLicenseUrlRest = new SubmissionCCLicenseUrlRest();
+ submissionCCLicenseUrlRest.setUrl(modelObject.getUrl());
+ submissionCCLicenseUrlRest.setId(modelObject.getId());
+
+ return submissionCCLicenseUrlRest;
+ }
+
+ @Override
+ public Class getModelClass() {
+ return SubmissionCCLicenseUrl.class;
+ }
+
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/exception/DSpaceApiExceptionControllerAdvice.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/exception/DSpaceApiExceptionControllerAdvice.java
index e0b3a86d18..d255b6fe27 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/exception/DSpaceApiExceptionControllerAdvice.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/exception/DSpaceApiExceptionControllerAdvice.java
@@ -29,6 +29,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
/**
@@ -54,8 +55,8 @@ public class DSpaceApiExceptionControllerAdvice extends ResponseEntityExceptionH
}
}
- @ExceptionHandler(IllegalArgumentException.class)
- protected void handleIllegalArgumentException(HttpServletRequest request, HttpServletResponse response,
+ @ExceptionHandler({IllegalArgumentException.class, MultipartException.class})
+ protected void handleWrongRequestException(HttpServletRequest request, HttpServletResponse response,
Exception ex) throws IOException {
sendErrorResponse(request, response, ex, ex.getMessage(), HttpServletResponse.SC_BAD_REQUEST);
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/RootHalLinkFactory.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/RootHalLinkFactory.java
index 55751435d4..7ce95aa18c 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/RootHalLinkFactory.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/RootHalLinkFactory.java
@@ -30,7 +30,7 @@ public class RootHalLinkFactory extends HalLinkFactory This parameter should be of type {@link org.dspace.app.rest.model.hateoas.HALResource}
+ */
+public abstract class ProcessHalLinkFactory extends HalLinkFactory {
+}
\ No newline at end of file
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/process/ProcessResourceHalLinkFactory.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/process/ProcessResourceHalLinkFactory.java
index 8325080861..041c4c651b 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/process/ProcessResourceHalLinkFactory.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/process/ProcessResourceHalLinkFactory.java
@@ -10,7 +10,6 @@ package org.dspace.app.rest.link.process;
import java.util.LinkedList;
import org.dspace.app.rest.RestResourceController;
-import org.dspace.app.rest.link.HalLinkFactory;
import org.dspace.app.rest.model.hateoas.ProcessResource;
import org.dspace.services.ConfigurationService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -19,25 +18,28 @@ import org.springframework.hateoas.Link;
import org.springframework.stereotype.Component;
/**
- * This class will provide the ProcessResource with links
+ * This HalLinkFactory provides the {@link ProcessResource} with links
*/
@Component
-public class ProcessResourceHalLinkFactory extends HalLinkFactory {
+public class ProcessResourceHalLinkFactory extends ProcessHalLinkFactory {
@Autowired
private ConfigurationService configurationService;
+ @Override
protected void addLinks(ProcessResource halResource, Pageable pageable, LinkedList list) throws Exception {
- String dspaceRestUrl = configurationService.getProperty("dspace.server.url");
+ String dspaceServerUrl = configurationService.getProperty("dspace.server.url");
list.add(
- buildLink("script", dspaceRestUrl + "/api/system/scripts/" + halResource.getContent().getScriptName()));
+ buildLink("script", dspaceServerUrl + "/api/system/scripts/" + halResource.getContent().getScriptName()));
}
+ @Override
protected Class getControllerClass() {
return RestResourceController.class;
}
+ @Override
protected Class getResourceClass() {
return ProcessResource.class;
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/process/SubmissionCCLicenseUrlResourceHalLinkFactory.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/process/SubmissionCCLicenseUrlResourceHalLinkFactory.java
new file mode 100644
index 0000000000..07d5e46c61
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/link/process/SubmissionCCLicenseUrlResourceHalLinkFactory.java
@@ -0,0 +1,73 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.link.process;
+
+import java.util.LinkedList;
+import java.util.Map;
+
+import org.dspace.app.rest.RestResourceController;
+import org.dspace.app.rest.link.HalLinkFactory;
+import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
+import org.dspace.app.rest.model.hateoas.SubmissionCCLicenseUrlResource;
+import org.dspace.services.RequestService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
+import org.springframework.hateoas.Link;
+import org.springframework.stereotype.Component;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.web.util.UriComponentsBuilder;
+
+/**
+ * This class will provide the SubmissionCCLicenseUrlResource with links
+ */
+@Component
+public class SubmissionCCLicenseUrlResourceHalLinkFactory
+ extends HalLinkFactory {
+
+ @Autowired
+ RequestService requestService;
+
+ /**
+ * Add a self link based on the search parameters
+ *
+ * @param halResource - The halResource
+ * @param pageable - The page information
+ * @param list - The list of present links
+ * @throws Exception
+ */
+ @Override
+ protected void addLinks(SubmissionCCLicenseUrlResource halResource, final Pageable pageable,
+ LinkedList list)
+ throws Exception {
+
+ halResource.removeLinks();
+ Map parameterMap = requestService.getCurrentRequest().getHttpServletRequest()
+ .getParameterMap();
+
+
+ UriComponentsBuilder uriComponentsBuilder = uriBuilder(getMethodOn().executeSearchMethods(
+ SubmissionCCLicenseUrlRest.CATEGORY, SubmissionCCLicenseUrlRest.PLURAL, "rightsByQuestions", null, null,
+ null, null, new LinkedMultiValueMap<>()));
+ for (String key : parameterMap.keySet()) {
+ uriComponentsBuilder.queryParam(key, parameterMap.get(key));
+ }
+
+ list.add(buildLink("self", uriComponentsBuilder.build().toUriString()));
+ }
+
+
+ @Override
+ protected Class getControllerClass() {
+ return RestResourceController.class;
+ }
+
+ @Override
+ protected Class getResourceClass() {
+ return SubmissionCCLicenseUrlResource.class;
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ExternalSourceEntryRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ExternalSourceEntryRest.java
index aa5dfa8cf2..06af7e2227 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ExternalSourceEntryRest.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ExternalSourceEntryRest.java
@@ -12,7 +12,7 @@ import org.dspace.app.rest.ExternalSourcesRestController;
/**
* This class serves as a REST representation for an entry of external data
*/
-public class ExternalSourceEntryRest extends BaseObjectRest {
+public class ExternalSourceEntryRest extends RestAddressableModel {
public static final String NAME = "externalSourceEntry";
public static final String PLURAL_NAME = "externalSourceEntries";
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ParameterRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ParameterRest.java
index 53eb2033b9..473426e533 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ParameterRest.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ParameterRest.java
@@ -25,16 +25,16 @@ public class ParameterRest {
*/
private String type;
- /**
- * The long name of the parameter
- */
- private String nameLong;
-
/**
* Boolean indicating whether the parameter is mandatory or not
*/
private boolean mandatory;
+ /**
+ * The long name of the parameter
+ */
+ private String nameLong;
+
public String getName() {
return name;
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ProcessFileTypesRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ProcessFileTypesRest.java
new file mode 100644
index 0000000000..ecceea107e
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ProcessFileTypesRest.java
@@ -0,0 +1,68 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.dspace.app.rest.RestResourceController;
+
+/**
+ * This class provides a way to list the filetypes present in a given Process by showing them as a list of Strings
+ * It'll be used by {@link org.dspace.app.rest.repository.ProcessFileTypesLinkRepository}
+ */
+public class ProcessFileTypesRest extends BaseObjectRest {
+
+ public static final String NAME = "filetypes";
+ public static final String PLURAL_NAME = "filetypes";
+ public static final String CATEGORY = RestAddressableModel.SYSTEM;
+
+ private List values;
+
+ /**
+ * Generic getter for the values
+ * @return the values value of this ProcessFileTypesRest
+ */
+ public List getValues() {
+ return values;
+ }
+
+ /**
+ * Generic setter for the values
+ * @param values The values to be set on this ProcessFileTypesRest
+ */
+ public void setValues(List values) {
+ this.values = values;
+ }
+
+ /**
+ * Adds a value to the list of FileType Strings
+ * @param value The value to be added
+ */
+ public void addValue(String value) {
+ if (values == null) {
+ values = new LinkedList<>();
+ }
+ values.add(value);
+ }
+
+ @Override
+ public String getCategory() {
+ return CATEGORY;
+ }
+
+ @Override
+ public Class getController() {
+ return RestResourceController.class;
+ }
+
+ @Override
+ public String getType() {
+ return NAME;
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ProcessRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ProcessRest.java
index 6d3ddfae43..399d880f3b 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ProcessRest.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/ProcessRest.java
@@ -20,12 +20,23 @@ import org.dspace.scripts.Process;
/**
* This class serves as a REST representation for the {@link Process} class
*/
+@LinksRest(links = {
+ @LinkRest(
+ name = ProcessRest.FILES,
+ method = "getFilesFromProcess"
+ ),
+ @LinkRest(
+ name = ProcessRest.FILE_TYPES,
+ method = "getFileTypesFromProcess"
+ )
+})
public class ProcessRest extends BaseObjectRest {
public static final String NAME = "process";
public static final String PLURAL_NAME = "processes";
public static final String CATEGORY = RestAddressableModel.SYSTEM;
-
+ public static final String FILES = "files";
+ public static final String FILE_TYPES = "filetypes";
public String getCategory() {
return CATEGORY;
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/PropertyRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/PropertyRest.java
new file mode 100644
index 0000000000..365a679019
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/PropertyRest.java
@@ -0,0 +1,62 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import org.dspace.app.rest.RestResourceController;
+
+/**
+ * This class acts as the REST representation of a DSpace configuration property.
+ * This class acts as a data holder for the PropertyResource
+ */
+public class PropertyRest extends BaseObjectRest {
+ public static final String NAME = "property";
+ public static final String CATEGORY = RestAddressableModel.CONFIGURATION;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public List getValues() {
+ return values;
+ }
+
+ public void setValues(List values) {
+ this.values = values;
+ }
+
+ public String name;
+ public List values;
+
+ @Override
+ @JsonIgnore
+ public String getId() {
+ return this.name;
+ }
+
+ @Override
+ public String getCategory() {
+ return CATEGORY;
+ }
+
+ @Override
+ public Class getController() {
+ return RestResourceController.class;
+ }
+
+ @Override
+ public String getType() {
+ return NAME;
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/RootRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/RootRest.java
index bb20ef9e43..3079f1a0c2 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/RootRest.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/RootRest.java
@@ -17,9 +17,9 @@ import org.dspace.app.rest.RootRestResourceController;
public class RootRest extends RestAddressableModel {
public static final String NAME = "root";
public static final String CATEGORY = RestModel.ROOT;
- private String dspaceURL;
+ private String dspaceUI;
private String dspaceName;
- private String dspaceRest;
+ private String dspaceServer;
public String getCategory() {
return CATEGORY;
@@ -33,13 +33,13 @@ public class RootRest extends RestAddressableModel {
return RootRestResourceController.class;
}
- public String getDspaceURL() {
+ public String getDspaceUI() {
- return dspaceURL;
+ return dspaceUI;
}
- public void setDspaceURL(String dspaceURL) {
- this.dspaceURL = dspaceURL;
+ public void setDspaceUI(String dspaceUI) {
+ this.dspaceUI = dspaceUI;
}
public String getDspaceName() {
@@ -50,12 +50,12 @@ public class RootRest extends RestAddressableModel {
this.dspaceName = dspaceName;
}
- public String getDspaceRest() {
- return dspaceRest;
+ public String getDspaceServer() {
+ return dspaceServer;
}
- public void setDspaceRest(String dspaceRest) {
- this.dspaceRest = dspaceRest;
+ public void setDspaceServer(String dspaceServerURL) {
+ this.dspaceServer = dspaceServerURL;
}
@Override
@@ -64,9 +64,9 @@ public class RootRest extends RestAddressableModel {
new EqualsBuilder().append(this.getCategory(), ((RootRest) object).getCategory())
.append(this.getType(), ((RootRest) object).getType())
.append(this.getController(), ((RootRest) object).getController())
- .append(this.getDspaceURL(), ((RootRest) object).getDspaceURL())
+ .append(this.getDspaceUI(), ((RootRest) object).getDspaceUI())
.append(this.getDspaceName(), ((RootRest) object).getDspaceName())
- .append(this.getDspaceRest(), ((RootRest) object).getDspaceRest())
+ .append(this.getDspaceServer(), ((RootRest) object).getDspaceServer())
.isEquals());
}
@@ -77,8 +77,8 @@ public class RootRest extends RestAddressableModel {
.append(this.getType())
.append(this.getController())
.append(this.getDspaceName())
- .append(this.getDspaceURL())
- .append(this.getDspaceRest())
+ .append(this.getDspaceUI())
+ .append(this.getDspaceServer())
.toHashCode();
}
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseFieldEnumRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseFieldEnumRest.java
new file mode 100644
index 0000000000..770eb25782
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseFieldEnumRest.java
@@ -0,0 +1,44 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model;
+
+/**
+ * This class is the REST representation of the CCLicenseFieldEnum model object and acts as a data sub object
+ * for the SubmissionCCLicenseFieldRest class.
+ * Refer to {@link org.dspace.license.CCLicenseFieldEnum} for explanation of the properties
+ */
+public class SubmissionCCLicenseFieldEnumRest {
+
+ private String id;
+ private String label;
+ private String description;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(final String label) {
+ this.label = label;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseFieldRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseFieldRest.java
new file mode 100644
index 0000000000..bcc90279dc
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseFieldRest.java
@@ -0,0 +1,59 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model;
+
+import java.util.List;
+
+/**
+ * This class is the REST representation of the CCLicenseField model object and acts as a data sub object
+ * for the SubmissionCCLicenseRest class.
+ * Refer to {@link org.dspace.license.CCLicenseField} for explanation of the properties
+ */
+public class SubmissionCCLicenseFieldRest {
+
+ private String id;
+
+ private String label;
+
+ private String description;
+
+ private List enums;
+
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(final String label) {
+ this.label = label;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(final String description) {
+ this.description = description;
+ }
+
+ public List getEnums() {
+ return enums;
+ }
+
+ public void setEnums(final List enums) {
+ this.enums = enums;
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseRest.java
new file mode 100644
index 0000000000..23589d5a46
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseRest.java
@@ -0,0 +1,74 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.dspace.app.rest.RestResourceController;
+
+/**
+ * This class is the REST representation of the CCLicense model object and acts as a data object
+ * for the SubmissionCCLicenseResource class.
+ * Refer to {@link org.dspace.license.CCLicense} for explanation of the properties
+ */
+public class SubmissionCCLicenseRest extends BaseObjectRest {
+ public static final String NAME = "submissioncclicense";
+ public static final String PLURAL = "submissioncclicenses";
+
+ public static final String CATEGORY = RestAddressableModel.CONFIGURATION;
+
+ private String id;
+
+ private String name;
+
+ private List fields;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(final String id) {
+ this.id = id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ public List getFields() {
+ return fields;
+ }
+
+ public void setFields(final List fields) {
+ this.fields = fields;
+ }
+
+ @JsonIgnore
+ @Override
+ public String getCategory() {
+ return CATEGORY;
+ }
+
+ @Override
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public String getType() {
+ return NAME;
+ }
+
+ @Override
+ @JsonIgnore
+ public Class getController() {
+ return RestResourceController.class;
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseUrlRest.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseUrlRest.java
new file mode 100644
index 0000000000..77263ba317
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/SubmissionCCLicenseUrlRest.java
@@ -0,0 +1,60 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import org.dspace.app.rest.RestResourceController;
+
+/**
+ * This class is the REST representation of the CCLicense URL String object and acts as a data object
+ * for the SubmissionCCLicenseUrlRest class.
+ */
+public class SubmissionCCLicenseUrlRest extends BaseObjectRest {
+ public static final String NAME = "submissioncclicenseUrl";
+ public static final String PLURAL = "submissioncclicenseUrls";
+ public static final String CATEGORY = RestAddressableModel.CONFIGURATION;
+
+
+ private String url;
+
+ @JsonIgnore
+ @Override
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(final String url) {
+ this.url = url;
+ }
+
+ @Override
+ @JsonProperty(access = JsonProperty.Access.READ_ONLY)
+ public String getType() {
+ return NAME;
+ }
+
+ @Override
+ public String getCategory() {
+ return SubmissionCCLicenseUrlRest.CATEGORY;
+ }
+
+ @Override
+ @JsonIgnore
+ public Class getController() {
+ return RestResourceController.class;
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/ProcessFileTypesResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/ProcessFileTypesResource.java
new file mode 100644
index 0000000000..75c26b95f5
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/ProcessFileTypesResource.java
@@ -0,0 +1,22 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model.hateoas;
+
+import org.dspace.app.rest.model.ProcessFileTypesRest;
+import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
+
+/**
+ * Resource object for {@link ProcessFileTypesRest}
+ */
+@RelNameDSpaceResource(ProcessFileTypesRest.NAME)
+public class ProcessFileTypesResource extends HALResource {
+
+ public ProcessFileTypesResource(ProcessFileTypesRest content) {
+ super(content);
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/PropertyResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/PropertyResource.java
new file mode 100644
index 0000000000..96df54ce9a
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/PropertyResource.java
@@ -0,0 +1,21 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model.hateoas;
+
+import org.dspace.app.rest.model.PropertyRest;
+import org.dspace.app.rest.utils.Utils;
+
+/**
+ * The purpose of this class is to wrap the information of the PropertyRest into a HAL resource
+ */
+public class PropertyResource extends DSpaceResource {
+
+ public PropertyResource(PropertyRest data, Utils utils) {
+ super(data, utils);
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/SubmissionCCLicenseResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/SubmissionCCLicenseResource.java
new file mode 100644
index 0000000000..fb041d2827
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/SubmissionCCLicenseResource.java
@@ -0,0 +1,23 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model.hateoas;
+
+import org.dspace.app.rest.model.SubmissionCCLicenseRest;
+import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
+import org.dspace.app.rest.utils.Utils;
+
+/**
+ * CCLicense HAL Resource. This resource adds the data from the REST object together with embedded objects
+ * and a set of links if applicable
+ */
+@RelNameDSpaceResource(SubmissionCCLicenseRest.NAME)
+public class SubmissionCCLicenseResource extends DSpaceResource {
+ public SubmissionCCLicenseResource(SubmissionCCLicenseRest submissionCCLicenseRest, Utils utils) {
+ super(submissionCCLicenseRest, utils);
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/SubmissionCCLicenseUrlResource.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/SubmissionCCLicenseUrlResource.java
new file mode 100644
index 0000000000..29ce7cf669
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/hateoas/SubmissionCCLicenseUrlResource.java
@@ -0,0 +1,23 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model.hateoas;
+
+import org.dspace.app.rest.model.SubmissionCCLicenseUrlRest;
+import org.dspace.app.rest.model.hateoas.annotations.RelNameDSpaceResource;
+import org.dspace.app.rest.utils.Utils;
+
+/**
+ * SubmissionCCLicenseUrl HAL Resource. This resource adds the data from the REST object together with embedded objects
+ * and a set of links if applicable
+ */
+@RelNameDSpaceResource(SubmissionCCLicenseUrlRest.NAME)
+public class SubmissionCCLicenseUrlResource extends DSpaceResource {
+ public SubmissionCCLicenseUrlResource(SubmissionCCLicenseUrlRest submissionCCLicenseUrlRest, Utils utils) {
+ super(submissionCCLicenseUrlRest, utils);
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/step/DataCCLicense.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/step/DataCCLicense.java
new file mode 100644
index 0000000000..32b3710d7c
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/step/DataCCLicense.java
@@ -0,0 +1,46 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model.step;
+
+import org.dspace.app.rest.model.BitstreamRest;
+
+/**
+ * Java Bean to expose the section creativecommons representing the CC License during in progress submission.
+ */
+public class DataCCLicense implements SectionData {
+
+ private String uri;
+
+ private String rights;
+
+ private BitstreamRest file;
+
+ public String getUri() {
+ return uri;
+ }
+
+ public void setUri(final String uri) {
+ this.uri = uri;
+ }
+
+ public String getRights() {
+ return rights;
+ }
+
+ public void setRights(final String rights) {
+ this.rights = rights;
+ }
+
+ public BitstreamRest getFile() {
+ return file;
+ }
+
+ public void setFile(final BitstreamRest file) {
+ this.file = file;
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/wrapper/SubmissionCCLicenseUrl.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/wrapper/SubmissionCCLicenseUrl.java
new file mode 100644
index 0000000000..68ff1166b4
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/model/wrapper/SubmissionCCLicenseUrl.java
@@ -0,0 +1,68 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.model.wrapper;
+
+/**
+ * This class represents a model implementation for {@link org.dspace.app.rest.model.SubmissionCCLicenseUrlRest}
+ * This will simply store a url and an id. it'll be used to create an object with these variables out of information
+ * that came from the back-end. This object will then be used in the
+ * {@link org.dspace.app.rest.converter.SubmissionCCLicenseUrlConverter} to turn it into its REST object
+ */
+public class SubmissionCCLicenseUrl {
+
+ /**
+ * The url for ths object
+ */
+ private String url;
+ /**
+ * The id for this object
+ */
+ private String id;
+
+ /**
+ * Default constructor with two parameters, url and id
+ * @param url The url of this object
+ * @param id The id of this object
+ */
+ public SubmissionCCLicenseUrl(String url, String id) {
+ this.url = url;
+ this.id = id;
+ }
+
+ /**
+ * Generic getter for the url
+ * @return the url value of this SubmissionCCLicenseUrl
+ */
+ public String getUrl() {
+ return url;
+ }
+
+ /**
+ * Generic setter for the url
+ * @param url The url to be set on this SubmissionCCLicenseUrl
+ */
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ /**
+ * Generic getter for the id
+ * @return the id value of this SubmissionCCLicenseUrl
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Generic setter for the id
+ * @param id The id to be set on this SubmissionCCLicenseUrl
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorityRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorityRestRepository.java
index 18120775d0..d5dda5a0bc 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorityRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorityRestRepository.java
@@ -8,19 +8,24 @@
package org.dspace.app.rest.repository;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Set;
+import org.dspace.app.rest.DiscoverableEndpointsService;
import org.dspace.app.rest.model.AuthorityRest;
+import org.dspace.app.rest.model.AuthorizationRest;
import org.dspace.app.rest.projection.Projection;
import org.dspace.app.rest.utils.AuthorityUtils;
import org.dspace.content.authority.ChoiceAuthority;
import org.dspace.content.authority.service.ChoiceAuthorityService;
import org.dspace.core.Context;
+import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
+import org.springframework.hateoas.Link;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
@@ -30,7 +35,8 @@ import org.springframework.stereotype.Component;
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
*/
@Component(AuthorityRest.CATEGORY + "." + AuthorityRest.NAME)
-public class AuthorityRestRepository extends DSpaceRestRepository {
+public class AuthorityRestRepository extends DSpaceRestRepository
+ implements InitializingBean {
@Autowired
private ChoiceAuthorityService cas;
@@ -38,6 +44,9 @@ public class AuthorityRestRepository extends DSpaceRestRepository getDomainClass() {
return AuthorityRest.class;
}
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ discoverableEndpointsService.register(this, Arrays.asList(
+ new Link("/api/" + AuthorizationRest.CATEGORY + "/" + AuthorizationRest.NAME + "/search",
+ AuthorizationRest.NAME + "-search")));
+ }
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorizationFeatureRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorizationFeatureRestRepository.java
index 418bebcdf5..62781fe8e8 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorizationFeatureRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorizationFeatureRestRepository.java
@@ -45,11 +45,10 @@ public class AuthorizationFeatureRestRepository extends DSpaceRestRepository findAll(Context context, Pageable pageable) {
- return converter.toRestPage(utils.getPage(authorizationFeatureService.findAll(),
- pageable), utils.obtainProjection());
+ return converter.toRestPage(authorizationFeatureService.findAll(), pageable, utils.obtainProjection());
}
- @PreAuthorize("hasAuthority('ADMIN')")
+ @PreAuthorize("permitAll()")
@Override
public AuthorizationFeatureRest findOne(Context context, String id) {
AuthorizationFeature authzFeature = authorizationFeatureService.find(id);
@@ -64,6 +63,6 @@ public class AuthorizationFeatureRestRepository extends DSpaceRestRepository findByResourceType(@Parameter(value = "type", required = true) String type,
Pageable pageable) {
List foundFeatures = authorizationFeatureService.findByResourceType(type);
- return converter.toRestPage(utils.getPage(foundFeatures, pageable), utils.obtainProjection());
+ return converter.toRestPage(foundFeatures, pageable, utils.obtainProjection());
}
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorizationRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorizationRestRepository.java
index fe15bbfbf7..175fcd49f9 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorizationRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/AuthorizationRestRepository.java
@@ -174,7 +174,7 @@ public class AuthorizationRestRepository extends DSpaceRestRepository findAll(Context context, Pageable pageable) {
try {
List bit = bitstreamFormatService.findAll(context);
- return converter.toRestPage(utils.getPage(bit, pageable), utils.obtainProjection());
+ return converter.toRestPage(bit, pageable, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java
index 2d29781c9b..71c02d4057 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BitstreamRestRepository.java
@@ -10,17 +10,14 @@ package org.dspace.app.rest.repository;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.exception.DSpaceBadRequestException;
+import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.model.patch.Patch;
-import org.dspace.app.rest.projection.Projection;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
@@ -34,7 +31,6 @@ import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
import org.springframework.security.access.prepost.PreAuthorize;
@@ -71,7 +67,7 @@ public class BitstreamRestRepository extends DSpaceObjectRestRepository findAll(Context context, Pageable pageable) {
- List bit = new ArrayList();
- Iterator it = null;
- int total = 0;
- try {
- total = bs.countTotal(context);
- it = bs.findAll(context, pageable.getPageSize(), Math.toIntExact(pageable.getOffset()));
- while (it.hasNext()) {
- bit.add(it.next());
- }
- } catch (SQLException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- Projection projection = utils.obtainProjection();
- Page page = new PageImpl<>(bit, pageable, total)
- .map((bitstream) -> converter.toRest(bitstream, projection));
- return page;
+ throw new RepositoryMethodNotImplementedException(BitstreamRest.NAME, "findAll");
}
@Override
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BrowseIndexRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BrowseIndexRestRepository.java
index 10f18e8e66..01277ff29b 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BrowseIndexRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BrowseIndexRestRepository.java
@@ -16,6 +16,7 @@ import org.dspace.browse.BrowseIndex;
import org.dspace.core.Context;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Component;
/**
@@ -27,6 +28,7 @@ import org.springframework.stereotype.Component;
public class BrowseIndexRestRepository extends DSpaceRestRepository {
@Override
+ @PreAuthorize("permitAll()")
public BrowseIndexRest findOne(Context context, String name) {
BrowseIndexRest bi = null;
BrowseIndex bix;
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BundleBitstreamLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BundleBitstreamLinkRepository.java
index 4b280fdbce..b0a4488e03 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BundleBitstreamLinkRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BundleBitstreamLinkRepository.java
@@ -15,7 +15,6 @@ import javax.servlet.http.HttpServletRequest;
import org.dspace.app.rest.model.BitstreamRest;
import org.dspace.app.rest.model.BundleRest;
import org.dspace.app.rest.projection.Projection;
-import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.BundleService;
@@ -52,8 +51,7 @@ public class BundleBitstreamLinkRepository extends AbstractDSpaceRestRepository
throw new ResourceNotFoundException("No such bundle: " + bundleId);
}
Pageable pageable = utils.getPageable(optionalPageable);
- Page page = utils.getPage(bundle.getBitstreams(), pageable);
- return converter.toRestPage(page, projection);
+ return converter.toRestPage(bundle.getBitstreams(), pageable, projection);
} catch (SQLException e) {
throw new RuntimeException(e);
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BundleRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BundleRestRepository.java
index d26ceeb2bf..f750743db6 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BundleRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/BundleRestRepository.java
@@ -74,11 +74,11 @@ public class BundleRestRepository extends DSpaceObjectRestRepository {
+public class ClaimedTaskRestRepository extends DSpaceRestRepository
+ implements InitializingBean {
private static final Logger log = Logger.getLogger(ClaimedTaskRestRepository.class);
@@ -78,6 +83,9 @@ public class ClaimedTaskRestRepository extends DSpaceRestRepository tasks = claimedTaskService.findByEperson(context, ep);
- return converter.toRestPage(utils.getPage(tasks, pageable), utils.obtainProjection());
+ return converter.toRestPage(tasks, pageable, utils.obtainProjection());
} else {
throw new RESTAuthorizationException("Only administrators can search for claimed tasks of other users");
}
@@ -188,4 +196,11 @@ public class ClaimedTaskRestRepository extends DSpaceRestRepository findAll(Context context, Pageable pageable) {
throw new RepositoryMethodNotImplementedException(ClaimedTaskRest.NAME, "findAll");
}
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ discoverableEndpointsService.register(this, Arrays.asList(
+ new Link("/api/" + ClaimedTaskRest.CATEGORY + "/" + ClaimedTaskRest.NAME + "/search",
+ ClaimedTaskRest.NAME + "-search")));
+ }
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CollectionBitstreamReadGroupLinkRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CollectionBitstreamReadGroupLinkRepository.java
index 57b17168ea..c1b322a490 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CollectionBitstreamReadGroupLinkRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CollectionBitstreamReadGroupLinkRepository.java
@@ -72,6 +72,9 @@ public class CollectionBitstreamReadGroupLinkRepository extends AbstractDSpaceRe
}
List bitstreamGroups = authorizeService
.getAuthorizedGroups(context, collection, Constants.DEFAULT_BITSTREAM_READ);
+ if (bitstreamGroups == null || bitstreamGroups.isEmpty()) {
+ return null;
+ }
Group bitstreamReadGroup = bitstreamGroups.get(0);
if (bitstreamReadGroup == null) {
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
index 934a4fc698..f273d6434e 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CollectionRestRepository.java
@@ -163,9 +163,10 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository findAuthorizedByCommunity(
- @Parameter(value = "uuid", required = true) UUID communityUuid, Pageable pageable) {
+ @SearchRestMethod(name = "findSubmitAuthorizedByCommunity")
+ public Page findSubmitAuthorizedByCommunity(
+ @Parameter(value = "uuid", required = true) UUID communityUuid, Pageable pageable,
+ @Parameter(value = "query") String q) {
try {
Context context = obtainContext();
Community com = communityService.find(context, communityUuid);
@@ -174,19 +175,26 @@ public class CollectionRestRepository extends DSpaceObjectRestRepository collections = cs.findAuthorized(context, com, Constants.ADD);
- return converter.toRestPage(utils.getPage(collections, pageable), utils.obtainProjection());
- } catch (SQLException e) {
+ List collections = cs.findCollectionsWithSubmit(q, context, com,
+ Math.toIntExact(pageable.getOffset()),
+ Math.toIntExact(pageable.getOffset() + pageable.getPageSize()));
+ int tot = cs.countCollectionsWithSubmit(q, context, com);
+ return converter.toRestPage(collections, pageable, tot , utils.obtainProjection());
+ } catch (SQLException | SearchServiceException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
- @SearchRestMethod(name = "findAuthorized")
- public Page findAuthorized(Pageable pageable) {
+ @SearchRestMethod(name = "findSubmitAuthorized")
+ public Page findSubmitAuthorized(@Parameter(value = "query") String q,
+ Pageable pageable) throws SearchServiceException {
try {
Context context = obtainContext();
- List collections = cs.findAuthorizedOptimized(context, Constants.ADD);
- return converter.toRestPage(utils.getPage(collections, pageable), utils.obtainProjection());
+ List collections = cs.findCollectionsWithSubmit(q, context, null,
+ Math.toIntExact(pageable.getOffset()),
+ Math.toIntExact(pageable.getOffset() + pageable.getPageSize()));
+ int tot = cs.countCollectionsWithSubmit(q, context, null);
+ return converter.toRestPage(collections, pageable, tot, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
index ca3183f265..885b680dce 100644
--- a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/CommunityRestRepository.java
@@ -201,7 +201,7 @@ public class CommunityRestRepository extends DSpaceObjectRestRepository findAllTop(Pageable pageable) {
try {
List communities = cs.findAllTop(obtainContext());
- return converter.toRestPage(utils.getPage(communities, pageable), utils.obtainProjection());
+ return converter.toRestPage(communities, pageable, utils.obtainProjection());
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
diff --git a/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ConfigurationRestRepository.java b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ConfigurationRestRepository.java
new file mode 100644
index 0000000000..caadb9f6f3
--- /dev/null
+++ b/dspace-server-webapp/src/main/java/org/dspace/app/rest/repository/ConfigurationRestRepository.java
@@ -0,0 +1,79 @@
+/**
+ * The contents of this file are subject to the license and copyright
+ * detailed in the LICENSE and NOTICE files at the root of the source
+ * tree and available online at
+ *
+ * http://www.dspace.org/license/
+ */
+package org.dspace.app.rest.repository;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.dspace.app.rest.exception.RepositoryMethodNotImplementedException;
+import org.dspace.app.rest.model.PropertyRest;
+import org.dspace.core.Context;
+import org.dspace.services.ConfigurationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.rest.webmvc.ResourceNotFoundException;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+
+/**
+ * This is the repository responsible of exposing configuration properties
+ */
+@Component(PropertyRest.CATEGORY + "." + PropertyRest.NAME)
+public class ConfigurationRestRepository extends DSpaceRestRepository {
+
+ private ConfigurationService configurationService;
+ private List exposedProperties;
+
+ @Autowired
+ public ConfigurationRestRepository(ConfigurationService configurationService) {
+ this.configurationService = configurationService;
+ this.exposedProperties = Arrays.asList(configurationService.getArrayProperty("rest.properties.exposed"));
+ }
+
+ /**
+ * Gets the value of a configuration property if it is exposed via REST
+ *
+ * Example:
+ *