Merge branch 'main' into CST-5249_suggestion

This commit is contained in:
frabacche
2024-02-13 12:03:12 +01:00
committed by GitHub
152 changed files with 3314 additions and 14074 deletions

View File

@@ -21,11 +21,11 @@ jobs:
# Also specify version of Java to use (this can allow us to optionally run tests on multiple JDKs in future)
matrix:
include:
# NOTE: Unit Tests include deprecated REST API v6 (as it has unit tests)
# NOTE: Unit Tests include a retry for occasionally failing tests
# - surefire.rerunFailingTestsCount => try again for flakey tests, and keep track of/report on number of retries
- type: "Unit Tests"
java: 11
mvnflags: "-DskipUnitTests=false -Pdspace-rest -Dsurefire.rerunFailingTestsCount=2"
mvnflags: "-DskipUnitTests=false -Dsurefire.rerunFailingTestsCount=2"
resultsdir: "**/target/surefire-reports/**"
# NOTE: ITs skip all code validation checks, as they are already done by Unit Test job.
# - enforcer.skip => Skip maven-enforcer-plugin rules

View File

@@ -102,6 +102,8 @@ jobs:
build_id: dspace-solr
image_name: dspace/dspace-solr
dockerfile_path: ./dspace/src/main/docker/dspace-solr/Dockerfile
# Must pass solrconfigs to the Dockerfile so that it can find the required Solr config files
dockerfile_additional_contexts: 'solrconfigs=./dspace/solr/'
secrets:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKER_ACCESS_TOKEN: ${{ secrets.DOCKER_ACCESS_TOKEN }}

View File

@@ -24,6 +24,12 @@ on:
dockerfile_context:
required: false
type: string
default: '.'
# Optionally a list of "additional_contexts" to pass to Dockerfile. Defaults to empty
dockerfile_additional_contexts:
required: false
type: string
default: ''
# If Docker image should have additional tag flavor details (e.g. a suffix), it may be passed in.
tags_flavor:
required: false
@@ -123,7 +129,9 @@ jobs:
id: docker_build
uses: docker/build-push-action@v5
with:
context: ${{ inputs.dockerfile_context || '.' }}
build-contexts: |
${{ inputs.dockerfile_additional_contexts }}
context: ${{ inputs.dockerfile_context }}
file: ${{ inputs.dockerfile_path }}
platforms: ${{ matrix.arch }}
# For pull requests, we run the Docker build (to ensure no PR changes break the build),

View File

@@ -19,7 +19,7 @@ RUN mkdir /install \
USER dspace
# Copy the DSpace source code (from local machine) into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
# Build DSpace (note: this build doesn't include the optional, deprecated "dspace-rest" webapp)
# Build DSpace
# Copy the dspace-installer directory to /install. Clean up the build to keep the docker image small
# Maven flags here ensure that we skip building test environment and skip all code verification checks.
# These flags speed up this compilation as much as reasonably possible.

View File

@@ -21,9 +21,9 @@ RUN mkdir /install \
USER dspace
# Copy the DSpace source code (from local machine) into the workdir (excluding .dockerignore contents)
ADD --chown=dspace . /app/
# Build DSpace (INCLUDING the optional, deprecated "dspace-rest" webapp)
# Build DSpace
# Copy the dspace-installer directory to /install. Clean up the build to keep the docker image small
RUN mvn --no-transfer-progress package -Pdspace-rest && \
RUN mvn --no-transfer-progress package && \
mv /app/dspace/target/${TARGET_DIR}/* /install && \
mvn clean
@@ -67,17 +67,10 @@ ENV CATALINA_OPTS=-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=*:800
# Link the DSpace 'server' webapp into Tomcat's webapps directory.
# This ensures that when we start Tomcat, it runs from /server path (e.g. http://localhost:8080/server/)
# Also link the v6.x (deprecated) REST API off the "/rest" path
RUN ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/server && \
ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest
RUN ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/server
# If you wish to run "server" webapp off the ROOT path, then comment out the above RUN, and uncomment the below RUN.
# You also MUST update the 'dspace.server.url' configuration to match.
# Please note that server webapp should only run on one path at a time.
#RUN mv /usr/local/tomcat/webapps/ROOT /usr/local/tomcat/webapps/ROOT.bk && \
# ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/ROOT && \
# ln -s $DSPACE_INSTALL/webapps/rest /usr/local/tomcat/webapps/rest
# ln -s $DSPACE_INSTALL/webapps/server /usr/local/tomcat/webapps/ROOT
# Overwrite the v6.x (deprecated) REST API's web.xml, so that we can run it on HTTP (defaults to requiring HTTPS)
# WARNING: THIS IS OBVIOUSLY INSECURE. NEVER DO THIS IN PRODUCTION.
COPY dspace/src/main/docker/test/rest_web.xml $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml
RUN sed -i -e "s|\${dspace.dir}|$DSPACE_INSTALL|" $DSPACE_INSTALL/webapps/rest/WEB-INF/web.xml

View File

@@ -1,5 +1,10 @@
version: "3.7"
networks:
# Default to using network named 'dspacenet' from docker-compose.yml.
# Its full name will be prepended with the project name (e.g. "-p d7" means it will be named "d7_dspacenet")
default:
name: ${COMPOSE_PROJECT_NAME}_dspacenet
external: true
services:
dspace-cli:
image: "${DOCKER_OWNER:-dspace}/dspace-cli:${DSPACE_VER:-latest}"
@@ -26,13 +31,8 @@ services:
- ./dspace/config:/dspace/config
entrypoint: /dspace/bin/dspace
command: help
networks:
- dspacenet
tty: true
stdin_open: true
volumes:
assetstore:
networks:
dspacenet:

View File

@@ -36,7 +36,7 @@ services:
depends_on:
- dspacedb
networks:
dspacenet:
- dspacenet
ports:
- published: 8080
target: 8080
@@ -89,8 +89,10 @@ services:
container_name: dspacesolr
image: "${DOCKER_OWNER:-dspace}/dspace-solr:${DSPACE_VER:-latest}"
build:
context: .
dockerfile: ./dspace/src/main/docker/dspace-solr/Dockerfile
context: ./dspace/src/main/docker/dspace-solr/
# Provide path to Solr configs necessary to build Docker image
additional_contexts:
solrconfigs: ./dspace/solr/
args:
SOLR_VERSION: "${SOLR_VER:-8.11}"
networks:

View File

@@ -528,7 +528,7 @@
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<artifactId>hamcrest</artifactId>
<scope>test</scope>
</dependency>
<dependency>
@@ -620,7 +620,7 @@
<dependency>
<groupId>com.maxmind.geoip2</groupId>
<artifactId>geoip2</artifactId>
<version>2.11.0</version>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
@@ -784,7 +784,7 @@
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.7.1</version>
<version>5.9</version>
</dependency>
<!-- Email templating -->
@@ -867,32 +867,32 @@
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>4.1.94.Final</version>
<version>4.1.106.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>4.1.94.Final</version>
<version>4.1.106.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport-native-unix-common</artifactId>
<version>4.1.94.Final</version>
<version>4.1.106.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>4.1.94.Final</version>
<version>4.1.106.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.94.Final</version>
<version>4.1.106.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>4.1.94.Final</version>
<version>4.1.106.Final</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
@@ -902,7 +902,7 @@
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<version>2.8.0</version>
<version>2.9.1</version>
<scope>test</scope>
</dependency>
<dependency>

View File

@@ -116,6 +116,17 @@ public final class CreateAdministrator {
protected CreateAdministrator()
throws Exception {
context = new Context();
try {
context.getDBConfig();
} catch (NullPointerException npr) {
// if database is null, there is no point in continuing. Prior to this exception and catch,
// NullPointerException was thrown, that wasn't very helpful.
throw new IllegalStateException("Problem connecting to database. This " +
"indicates issue with either network or version (or possibly some other). " +
"If you are running this in docker-compose, please make sure dspace-cli was " +
"built from the same sources as running dspace container AND that they are in " +
"the same project/network.");
}
groupService = EPersonServiceFactory.getInstance().getGroupService();
ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
}

View File

@@ -895,7 +895,7 @@ public class AuthorizeServiceImpl implements AuthorizeService {
return true;
}
} catch (SearchServiceException e) {
log.error("Failed getting getting community/collection admin status for "
log.error("Failed getting community/collection admin status for "
+ context.getCurrentUser().getEmail() + " The search error is: " + e.getMessage()
+ " The search resourceType filter was: " + query);
}

View File

@@ -458,10 +458,15 @@ public class BitstreamServiceImpl extends DSpaceObjectServiceImpl<Bitstream> imp
@Override
public Bitstream findByIdOrLegacyId(Context context, String id) throws SQLException {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
try {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
}
} catch (IllegalArgumentException e) {
// Not a valid legacy ID or valid UUID
return null;
}
}

View File

@@ -562,10 +562,15 @@ public class BundleServiceImpl extends DSpaceObjectServiceImpl<Bundle> implement
@Override
public Bundle findByIdOrLegacyId(Context context, String id) throws SQLException {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
try {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
}
} catch (IllegalArgumentException e) {
// Not a valid legacy ID or valid UUID
return null;
}
}

View File

@@ -895,10 +895,15 @@ public class CollectionServiceImpl extends DSpaceObjectServiceImpl<Collection> i
@Override
public Collection findByIdOrLegacyId(Context context, String id) throws SQLException {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
try {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
}
} catch (IllegalArgumentException e) {
// Not a valid legacy ID or valid UUID
return null;
}
}

View File

@@ -694,10 +694,15 @@ public class CommunityServiceImpl extends DSpaceObjectServiceImpl<Community> imp
@Override
public Community findByIdOrLegacyId(Context context, String id) throws SQLException {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
try {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
}
} catch (IllegalArgumentException e) {
// Not a valid legacy ID or valid UUID
return null;
}
}

View File

@@ -1435,16 +1435,6 @@ prevent the generation of resource policy entry values with null dspace_object a
}
}
@Override
public Iterator<Item> findByMetadataQuery(Context context, List<List<MetadataField>> listFieldList,
List<String> query_op, List<String> query_val, List<UUID> collectionUuids,
String regexClause, int offset, int limit)
throws SQLException, AuthorizeException, IOException {
return itemDAO
.findByMetadataQuery(context, listFieldList, query_op, query_val, collectionUuids, regexClause, offset,
limit);
}
@Override
public DSpaceObject getAdminObject(Context context, Item item, int action) throws SQLException {
DSpaceObject adminObject = null;
@@ -1618,10 +1608,15 @@ prevent the generation of resource policy entry values with null dspace_object a
@Override
public Item findByIdOrLegacyId(Context context, String id) throws SQLException {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
try {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
}
} catch (IllegalArgumentException e) {
// Not a valid legacy ID or valid UUID
return null;
}
}

View File

@@ -156,7 +156,8 @@ public class DCInputAuthority extends SelfNamedPlugin implements ChoiceAuthority
int found = 0;
List<Choice> v = new ArrayList<Choice>();
for (int i = 0; i < valuesLocale.length; ++i) {
if (query == null || StringUtils.containsIgnoreCase(valuesLocale[i], query)) {
// In a DCInputAuthority context, a user will want to query the labels, not the values
if (query == null || StringUtils.containsIgnoreCase(labelsLocale[i], query)) {
if (found >= start && v.size() < limit) {
v.add(new Choice(null, valuesLocale[i], labelsLocale[i]));
if (valuesLocale[i].equalsIgnoreCase(query)) {

View File

@@ -11,7 +11,6 @@ import java.sql.SQLException;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import org.dspace.content.Collection;
import org.dspace.content.Community;
@@ -80,10 +79,6 @@ public interface ItemDAO extends DSpaceObjectLegacySupportDAO<Item> {
public Iterator<Item> findByMetadataField(Context context, MetadataField metadataField, String value,
boolean inArchive) throws SQLException;
public Iterator<Item> findByMetadataQuery(Context context, List<List<MetadataField>> listFieldList,
List<String> query_op, List<String> query_val, List<UUID> collectionUuids,
String regexClause, int offset, int limit) throws SQLException;
public Iterator<Item> findByAuthorityValue(Context context, MetadataField metadataField, String authority,
boolean inArchive) throws SQLException;

View File

@@ -12,7 +12,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import javax.persistence.criteria.CriteriaBuilder;
@@ -24,20 +23,10 @@ import org.dspace.content.Collection;
import org.dspace.content.Item;
import org.dspace.content.Item_;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataValue;
import org.dspace.content.dao.ItemDAO;
import org.dspace.core.AbstractHibernateDSODAO;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.hibernate.Criteria;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.hibernate.type.StandardBasicTypes;
/**
* Hibernate implementation of the Database Access Object interface class for the Item object.
@@ -174,120 +163,6 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO<Item> implements ItemDA
return iterate(query);
}
enum OP {
equals {
public Criterion buildPredicate(String val, String regexClause) {
return Property.forName("mv.value").eq(val);
}
},
not_equals {
public Criterion buildPredicate(String val, String regexClause) {
return OP.equals.buildPredicate(val, regexClause);
}
},
like {
public Criterion buildPredicate(String val, String regexClause) {
return Property.forName("mv.value").like(val);
}
},
not_like {
public Criterion buildPredicate(String val, String regexClause) {
return OP.like.buildPredicate(val, regexClause);
}
},
contains {
public Criterion buildPredicate(String val, String regexClause) {
return Property.forName("mv.value").like("%" + val + "%");
}
},
doesnt_contain {
public Criterion buildPredicate(String val, String regexClause) {
return OP.contains.buildPredicate(val, regexClause);
}
},
exists {
public Criterion buildPredicate(String val, String regexClause) {
return Property.forName("mv.value").isNotNull();
}
},
doesnt_exist {
public Criterion buildPredicate(String val, String regexClause) {
return OP.exists.buildPredicate(val, regexClause);
}
},
matches {
public Criterion buildPredicate(String val, String regexClause) {
return Restrictions.sqlRestriction(regexClause, val, StandardBasicTypes.STRING);
}
},
doesnt_match {
public Criterion buildPredicate(String val, String regexClause) {
return OP.matches.buildPredicate(val, regexClause);
}
};
public abstract Criterion buildPredicate(String val, String regexClause);
}
@Override
@Deprecated
public Iterator<Item> findByMetadataQuery(Context context, List<List<MetadataField>> listFieldList,
List<String> query_op, List<String> query_val, List<UUID> collectionUuids,
String regexClause, int offset, int limit) throws SQLException {
Criteria criteria = getHibernateSession(context).createCriteria(Item.class, "item");
criteria.setFirstResult(offset);
criteria.setMaxResults(limit);
if (!collectionUuids.isEmpty()) {
DetachedCriteria dcollCriteria = DetachedCriteria.forClass(Collection.class, "coll");
dcollCriteria.setProjection(Projections.property("coll.id"));
dcollCriteria.add(Restrictions.eqProperty("coll.id", "item.owningCollection"));
dcollCriteria.add(Restrictions.in("coll.id", collectionUuids));
criteria.add(Subqueries.exists(dcollCriteria));
}
int index = Math.min(listFieldList.size(), Math.min(query_op.size(), query_val.size()));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < index; i++) {
OP op = OP.valueOf(query_op.get(i));
if (op == null) {
log.warn("Skipping Invalid Operator: " + query_op.get(i));
continue;
}
if (op == OP.matches || op == OP.doesnt_match) {
if (regexClause.isEmpty()) {
log.warn("Skipping Unsupported Regex Operator: " + query_op.get(i));
continue;
}
}
DetachedCriteria subcriteria = DetachedCriteria.forClass(MetadataValue.class, "mv");
subcriteria.add(Property.forName("mv.dSpaceObject").eqProperty("item.id"));
subcriteria.setProjection(Projections.property("mv.dSpaceObject"));
if (!listFieldList.get(i).isEmpty()) {
subcriteria.add(Restrictions.in("metadataField", listFieldList.get(i)));
}
subcriteria.add(op.buildPredicate(query_val.get(i), regexClause));
if (op == OP.exists || op == OP.equals || op == OP.like || op == OP.contains || op == OP.matches) {
criteria.add(Subqueries.exists(subcriteria));
} else {
criteria.add(Subqueries.notExists(subcriteria));
}
}
criteria.addOrder(Order.asc("item.id"));
log.debug(String.format("Running custom query with %d filters", index));
return ((List<Item>) criteria.list()).iterator();
}
@Override
public Iterator<Item> findByAuthorityValue(Context context, MetadataField metadataField, String authority,
boolean inArchive) throws SQLException {

View File

@@ -23,7 +23,6 @@ import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.EntityType;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataValue;
import org.dspace.content.Thumbnail;
import org.dspace.content.WorkspaceItem;
@@ -749,11 +748,6 @@ public interface ItemService
String schema, String element, String qualifier, String value)
throws SQLException, AuthorizeException, IOException;
public Iterator<Item> findByMetadataQuery(Context context, List<List<MetadataField>> listFieldList,
List<String> query_op, List<String> query_val, List<UUID> collectionUuids,
String regexClause, int offset, int limit)
throws SQLException, AuthorizeException, IOException;
/**
* Find all the items in the archive with a given authority key value
* in the indicated metadata field.

View File

@@ -7,14 +7,20 @@
*/
package org.dspace.discovery;
import static org.dspace.discovery.IndexClientOptions.TYPE_OPTION;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
@@ -51,6 +57,17 @@ public class IndexClient extends DSpaceRunnable<IndexDiscoveryScriptConfiguratio
return;
}
String type = null;
if (commandLine.hasOption(TYPE_OPTION)) {
List<String> indexableObjectTypes = IndexObjectFactoryFactory.getInstance().getIndexFactories().stream()
.map((indexFactory -> indexFactory.getType())).collect(Collectors.toList());
type = commandLine.getOptionValue(TYPE_OPTION);
if (!indexableObjectTypes.contains(type)) {
handler.handleException(String.format("%s is not a valid indexable object type, options: %s",
type, Arrays.toString(indexableObjectTypes.toArray())));
}
}
/** Acquire from dspace-services in future */
/**
* new DSpace.getServiceManager().getServiceByName("org.dspace.discovery.SolrIndexer");
@@ -113,6 +130,10 @@ public class IndexClient extends DSpaceRunnable<IndexDiscoveryScriptConfiguratio
} else if (indexClientOptions == IndexClientOptions.BUILD ||
indexClientOptions == IndexClientOptions.BUILDANDSPELLCHECK) {
handler.logInfo("(Re)building index from scratch.");
if (StringUtils.isNotBlank(type)) {
handler.logWarning(String.format("Type option, %s, not applicable for entire index rebuild option, b" +
", type will be ignored", TYPE_OPTION));
}
indexer.deleteIndex();
indexer.createIndex(context);
if (indexClientOptions == IndexClientOptions.BUILDANDSPELLCHECK) {
@@ -133,14 +154,14 @@ public class IndexClient extends DSpaceRunnable<IndexDiscoveryScriptConfiguratio
} else if (indexClientOptions == IndexClientOptions.UPDATE ||
indexClientOptions == IndexClientOptions.UPDATEANDSPELLCHECK) {
handler.logInfo("Updating Index");
indexer.updateIndex(context, false);
indexer.updateIndex(context, false, type);
if (indexClientOptions == IndexClientOptions.UPDATEANDSPELLCHECK) {
checkRebuildSpellCheck(commandLine, indexer);
}
} else if (indexClientOptions == IndexClientOptions.FORCEUPDATE ||
indexClientOptions == IndexClientOptions.FORCEUPDATEANDSPELLCHECK) {
handler.logInfo("Updating Index");
indexer.updateIndex(context, true);
indexer.updateIndex(context, true, type);
if (indexClientOptions == IndexClientOptions.FORCEUPDATEANDSPELLCHECK) {
checkRebuildSpellCheck(commandLine, indexer);
}

View File

@@ -8,8 +8,13 @@
package org.dspace.discovery;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.dspace.discovery.indexobject.factory.IndexObjectFactoryFactory;
/**
* This Enum holds all the possible options and combinations for the Index discovery script
@@ -29,6 +34,8 @@ public enum IndexClientOptions {
FORCEUPDATEANDSPELLCHECK,
HELP;
public static final String TYPE_OPTION = "t";
/**
* This method resolves the CommandLine parameters to figure out which action the index-discovery script should
* perform
@@ -71,11 +78,15 @@ public enum IndexClientOptions {
protected static Options constructOptions() {
Options options = new Options();
List<String> indexableObjectTypes = IndexObjectFactoryFactory.getInstance().getIndexFactories().stream()
.map((indexFactory -> indexFactory.getType())).collect(Collectors.toList());
options
.addOption("r", "remove", true, "remove an Item, Collection or Community from index based on its handle");
options.addOption("i", "index", true,
"add or update an Item, Collection or Community based on its handle or uuid");
options.addOption(TYPE_OPTION, "type", true, "reindex only specific type of " +
"(re)indexable objects; options: " + Arrays.toString(indexableObjectTypes.toArray()));
options.addOption("c", "clean", false,
"clean existing index removing any documents that no longer exist in the db");
options.addOption("d", "delete", false,

View File

@@ -146,10 +146,15 @@ public class EPersonServiceImpl extends DSpaceObjectServiceImpl<EPerson> impleme
@Override
public EPerson findByIdOrLegacyId(Context context, String id) throws SQLException {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
try {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
}
} catch (IllegalArgumentException e) {
// Not a valid legacy ID or valid UUID
return null;
}
}

View File

@@ -872,10 +872,15 @@ public class GroupServiceImpl extends DSpaceObjectServiceImpl<Group> implements
@Override
public Group findByIdOrLegacyId(Context context, String id) throws SQLException {
if (org.apache.commons.lang3.StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUIDUtils.fromString(id));
try {
if (StringUtils.isNumeric(id)) {
return findByLegacyId(context, Integer.parseInt(id));
} else {
return find(context, UUID.fromString(id));
}
} catch (IllegalArgumentException e) {
// Not a valid legacy ID or valid UUID
return null;
}
}

View File

@@ -81,6 +81,7 @@ import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.util.NamedList;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Collection;
@@ -146,6 +147,8 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
private SolrStatisticsCore solrStatisticsCore;
@Autowired
private GeoIpService geoIpService;
@Autowired
private AuthorizeService authorizeService;
/** URL to the current-year statistics core. Prior-year shards will have a year suffixed. */
private String statisticsCoreURL;
@@ -219,6 +222,16 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
@Override
public void postView(DSpaceObject dspaceObject, HttpServletRequest request,
EPerson currentUser, String referrer) {
Context context = new Context();
// Do not record statistics for Admin users
try {
if (authorizeService.isAdmin(context, currentUser)) {
return;
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
if (solr == null) {
return;
}

View File

@@ -68,8 +68,8 @@ public class ProcessBuilder extends AbstractBuilder<Process, ProcessService> {
public ProcessBuilder withStartAndEndTime(String startTime, String endTime) throws ParseException {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd/MM/yyyy");
process.setStartTime(simpleDateFormat.parse(startTime));
process.setFinishedTime(simpleDateFormat.parse(endTime));
process.setStartTime(startTime == null ? null : simpleDateFormat.parse(startTime));
process.setFinishedTime(endTime == null ? null : simpleDateFormat.parse(endTime));
return this;
}

View File

@@ -156,7 +156,7 @@
<!-- As our Parent POM sets this to 'test' scope, we must override it -->
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<artifactId>hamcrest</artifactId>
<scope>compile</scope>
</dependency>
<dependency>

View File

@@ -450,6 +450,16 @@ public class XOAI {
doc.addField("item.communities", "com_" + com.getHandle().replace("/", "_"));
}
boolean hasBitstream = false;
for (Bundle b : item.getBundles("ORIGINAL")) {
if (b.getBitstreams().size() > 0) {
hasBitstream = true;
}
}
doc.addField("item.hasbitstream", hasBitstream);
List<MetadataValue> allData = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY);
for (MetadataValue dc : allData) {
MetadataField field = dc.getMetadataField();

View File

@@ -0,0 +1,57 @@
/**
* 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.xoai.filter;
import java.sql.SQLException;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.xoai.data.DSpaceItem;
import org.dspace.xoai.filter.results.SolrFilterResult;
/**
* Created by Philip Vissenaekens (philip at atmire dot com)
* Date: 21/04/15
* Time: 15:18
*/
public class ItemsWithBitstreamFilter extends DSpaceFilter {
private static Logger log = LogManager.getLogger(ItemsWithBitstreamFilter.class);
private static final HandleService handleService
= HandleServiceFactory.getInstance().getHandleService();
@Override
public SolrFilterResult buildSolrQuery() {
return new SolrFilterResult("item.hasbitstream:true");
}
@Override
public boolean isShown(DSpaceItem item) {
try {
String handle = DSpaceItem.parseHandle(item.getIdentifier());
if (handle == null) {
return false;
}
Item dspaceItem = (Item) handleService.resolveToObject(context, handle);
for (Bundle b : dspaceItem.getBundles("ORIGINAL")) {
if (b.getBitstreams().size() > 0) {
return true;
}
}
} catch (SQLException e) {
log.error(e.getMessage(), e);
}
return false;
}
}

View File

@@ -11,6 +11,8 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import com.lyncode.xoai.dataprovider.xml.xoai.Element;
@@ -21,6 +23,7 @@ import org.apache.logging.log4j.Logger;
import org.dspace.app.util.factory.UtilServiceFactory;
import org.dspace.app.util.service.MetadataExposureService;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
@@ -114,23 +117,21 @@ public class ItemUtils {
log.error("Null bitstream found, check item uuid: " + item.getID());
break;
}
boolean primary = false;
// Check if current bitstream is in original bundle + 1 of the 2 following
// Bitstream = primary bitstream in bundle -> true
// No primary bitstream found in bundle-> only the first one gets flagged as "primary"
if (b.getName() != null && b.getName().equals("ORIGINAL") && (b.getPrimaryBitstream() != null
&& b.getPrimaryBitstream().getID() == bit.getID()
|| b.getPrimaryBitstream() == null && bit.getID() == bits.get(0).getID())) {
primary = true;
}
Element bitstream = create("bitstream");
bitstreams.getElement().add(bitstream);
String url = "";
String bsName = bit.getName();
String sid = String.valueOf(bit.getSequenceID());
String baseUrl = configurationService.getProperty("oai.bitstream.baseUrl");
String handle = null;
// get handle of parent Item of this bitstream, if there
// is one:
List<Bundle> bn = bit.getBundles();
if (!bn.isEmpty()) {
List<Item> bi = bn.get(0).getItems();
if (!bi.isEmpty()) {
handle = bi.get(0).getHandle();
}
}
url = baseUrl + "/bitstreams/" + bit.getID().toString() + "/download";
String url = baseUrl + "/bitstreams/" + bit.getID().toString() + "/download";
String cks = bit.getChecksum();
String cka = bit.getChecksumAlgorithm();
@@ -147,18 +148,65 @@ public class ItemUtils {
if (description != null) {
bitstream.getField().add(createValue("description", description));
}
// Add bitstream embargo information (READ policy present, for Anonymous group with a start date)
addResourcePolicyInformation(context, bit, bitstream);
bitstream.getField().add(createValue("format", bit.getFormat(context).getMIMEType()));
bitstream.getField().add(createValue("size", "" + bit.getSizeBytes()));
bitstream.getField().add(createValue("url", url));
bitstream.getField().add(createValue("checksum", cks));
bitstream.getField().add(createValue("checksumAlgorithm", cka));
bitstream.getField().add(createValue("sid", bit.getSequenceID() + ""));
// Add primary bitstream field to allow locating easily the primary bitstream information
bitstream.getField().add(createValue("primary", primary + ""));
}
}
return bundles;
}
/**
* This method will add metadata information about associated resource policies for a give bitstream.
* It will parse of relevant policies and add metadata information
* @param context
* @param bitstream the bitstream object
* @param bitstreamEl the bitstream metadata object to add resource policy information to
* @throws SQLException
*/
private static void addResourcePolicyInformation(Context context, Bitstream bitstream, Element bitstreamEl)
throws SQLException {
// Pre-filter access policies by DSO (bitstream) and Action (READ)
List<ResourcePolicy> policies = authorizeService.getPoliciesActionFilter(context, bitstream, Constants.READ);
// Create resourcePolicies container
Element resourcePolicies = create("resourcePolicies");
for (ResourcePolicy policy : policies) {
String groupName = policy.getGroup() != null ? policy.getGroup().getName() : null;
String user = policy.getEPerson() != null ? policy.getEPerson().getName() : null;
String action = Constants.actionText[policy.getAction()];
Date startDate = policy.getStartDate();
Date endDate = policy.getEndDate();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
Element resourcePolicyEl = create("resourcePolicy");
resourcePolicyEl.getField().add(createValue("group", groupName));
resourcePolicyEl.getField().add(createValue("user", user));
resourcePolicyEl.getField().add(createValue("action", action));
if (startDate != null) {
resourcePolicyEl.getField().add(createValue("start-date", formatter.format(startDate)));
}
if (endDate != null) {
resourcePolicyEl.getField().add(createValue("end-date", formatter.format(endDate)));
}
// Add resourcePolicy to list of resourcePolicies
resourcePolicies.getElement().add(resourcePolicyEl);
}
// Add list of resource policies to the corresponding Bitstream XML Element
bitstreamEl.getElement().add(resourcePolicies);
}
private static Element createLicenseElement(Context context, Item item)
throws SQLException, AuthorizeException, IOException {
Element license = create("license");
@@ -178,7 +226,7 @@ public class ItemUtils {
license.getField().add(createValue("bin", Base64Utils.encode(out.toString())));
} else {
log.info("Missing READ rights for license bitstream. Did not include license bitstream for item: "
+ item.getID() + ".");
+ item.getID() + ".");
}
}
}

View File

@@ -0,0 +1,35 @@
/**
* 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.xoai.tests.stylesheets;
import static org.dspace.xoai.tests.support.XmlMatcherBuilder.xml;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import org.dspace.xoai.tests.support.XmlMatcherBuilder;
import org.junit.Test;
public class RioxxXslTest extends AbstractXSLTest {
@Test
public void rioxxCanTransformInput() throws Exception {
String result = apply("rioxx.xsl").to(resource("xoai-rioxx-test.xml"));
assertThat(result, is(rioxx().withXPath("//dc:title", equalTo("The Intercorrelation Between " +
"Executive Function, Physics Problem Solving, Mathematical, and Matrix Reasoning Skills: " +
"Reflections from a Small-Scale Experiment"))));
}
private XmlMatcherBuilder rioxx() {
return xml()
.withNamespace("rioxx", "http://www.rioxx.net/schema/v3.0/rioxx/")
.withNamespace("rioxxterms", "http://docs.rioxx.net/schema/v3.0/rioxxterms/")
.withNamespace("dcterms", "http://purl.org/dc/terms/")
.withNamespace("dc", "http://purl.org/dc/elements/1.1/");
}
}

View File

@@ -0,0 +1,89 @@
<?xml version='1.0' encoding='UTF-8'?><!--
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/
-->
<rioxx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.rioxx.net/schema/v3.0/rioxx/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:rioxxterms="http://docs.rioxx.net/schema/v3.0/rioxxterms/">
<dc:description>Data on Secchi disc depth (the depth at which a standard white disc lowered into the water just becomes invisible to a surface observer) show that water clarity in the North Sea declined during the 20th century, with likely consequences for marine primary production. However, the causes of this trend remain unknown. Here we analyse the hypothesis that changes in the North Sea's wave climate were largely responsible by causing an increase in the concentrations of suspended particulate matter (SPM) in the water column through the resuspension of seabed sediments. First, we analysed the broad-scale statistical relationships between SPM and bed shear stress due to waves and tides. We used hindcasts of wave and current data to construct a spacetime dataset of bed shear stress between 1997 and 2017 across the northwest European Continental Shelf and compared the results with satellite-derived SPM concentrations. Bed shear stress was found to drive most of the inter-annual variation in SPM in the hydrographically mixed waters of the central and southern North Sea. We then used a long-term wave reanalysis to construct a time series of bed shear stress from 1900 to 2010. This shows that bed shear stress increased significantly across much of the shelf during this period, with increases of over 20% in the southeastern North Sea. An increase in bed shear stress of this magnitude would have resulted in a large reduction in water clarity. Wave-driven processes are rarely included in projections of climate change impacts on marine ecosystems, but our analysis indicates that this should be reconsidered for shelf sea regions.</dc:description>
<dc:language>en</dc:language>
<rioxxterms:publisher>
<rioxxterms:name>European Geosciences Union</rioxxterms:name>
<rioxxterms:id>https://isni.org/isni/0000000110927289</rioxxterms:id>
</rioxxterms:publisher>
<dc:source>1812-0792</dc:source>
<dc:title>Increasing turbidity in the North Sea during the 20th century due to changing wave climate</dc:title>
<dcterms:dateAccepted>2019-10-02</dcterms:dateAccepted>
<rioxxterms:creator
first-named-author="true">
<rioxxterms:name>Wilson, Robert J.</rioxxterms:name>
<rioxxterms:id>https://orcid.org/0000-0002-0592-366X</rioxxterms:id>
</rioxxterms:creator>
<rioxxterms:creator>
<rioxxterms:name>Heath, Michael R.</rioxxterms:name>
<rioxxterms:id>https://orcid.org/0000-0001-6602-3107</rioxxterms:id>
<rioxxterms:id> https://viaf.org/viaf/15147423189944882613</rioxxterms:id>
</rioxxterms:creator>
<rioxxterms:publication_date>2019-12-09</rioxxterms:publication_date>
<rioxxterms:record_public_release_date>2019-10-15</rioxxterms:record_public_release_date>
<dc:type>https://purl.org/coar/resource_type/c_2df8fbb1</dc:type>
<rioxxterms:grant
funder_name="Australian Research Council"
funder_id="https://ror.org/05mmh0f86">
DP190101507
</rioxxterms:grant>
<rioxxterms:grant
funder_name="John Templeton Foundation"
funder_id="https://ror.org/035tnyy05">
61387
</rioxxterms:grant>
<dc:relation
rel="item"
type="application/pdf"
coar_type="https://purl.org/coar/resource_type/c_6501"
coar_version="https://purl.org/coar/version/c_ab4af688f83e57aa"
deposit_date="2019-12-11"
resource_exposed_date="2019-12-11"
access_rights_="https://purl.org/coar/access_right/c_abf2"
license_ref="https://creativecommons.org/licenses/by-nc-nd/4.0/">
https://strathprints.strath.ac.uk/70117/7/Wilson_Heath_OS2019_Increasing_turbidity_in_the_North_Sea_during_the_20th_century.pdf
</dc:relation>
<!-- Other expressions (or 'instances') - publisher version -->
<rioxxterms:ext_relation
rel="cite-as"
coar_type="https://purl.org/coar/resource_type/c_6501"
coar_version="https://purl.org/coar/version/c_970fb48d4fbd8a85">
https://doi.org/10.1007/s11229-020-02724-x
</rioxxterms:ext_relation>
<!-- related dataset -->
<rioxxterms:ext_relation
rel="cite-as"
coar_type="https://purl.org/coar/resource_type/c_ddb1">
https://doi.org/10.15129/5d28213e-8f9f-402a-b550-fc588518cb8b
</rioxxterms:ext_relation >
<!-- related software -->
<rioxxterms:ext_relation
rel="cite-as"
coar_type="https://purl.org/coar/resource_type/QH80-2R4E">
https://doi.org/10.5281/zenodo.3478185
</rioxxterms:ext_relation>
</rioxx>

View File

@@ -0,0 +1,92 @@
<?xml version='1.0' encoding='UTF-8'?>
<!--
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/
-->
<rioxx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.rioxx.net/schema/v3.0/rioxx/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:rioxxterms="http://docs.rioxx.net/schema/v3.0/rioxxterms/">
<dc:description>Data on Secchi disc depth (the depth at which a standard white disc lowered into the water just becomes invisible to a surface observer) show that water clarity in the North Sea declined during the 20th century, with likely consequences for marine primary production. However, the causes of this trend remain unknown. Here we analyse the hypothesis that changes in the North Sea's wave climate were largely responsible by causing an increase in the concentrations of suspended particulate matter (SPM) in the water column through the resuspension of seabed sediments. First, we analysed the broad-scale statistical relationships between SPM and bed shear stress due to waves and tides. We used hindcasts of wave and current data to construct a spacetime dataset of bed shear stress between 1997 and 2017 across the northwest European Continental Shelf and compared the results with satellite-derived SPM concentrations. Bed shear stress was found to drive most of the inter-annual variation in SPM in the hydrographically mixed waters of the central and southern North Sea. We then used a long-term wave reanalysis to construct a time series of bed shear stress from 1900 to 2010. This shows that bed shear stress increased significantly across much of the shelf during this period, with increases of over 20% in the southeastern North Sea. An increase in bed shear stress of this magnitude would have resulted in a large reduction in water clarity. Wave-driven processes are rarely included in projections of climate change impacts on marine ecosystems, but our analysis indicates that this should be reconsidered for shelf sea regions.</dc:description>
<dc:language>en</dc:language>
<rioxxterms:publisher>
<rioxxterms:name>European Geosciences Union</rioxxterms:name>
<rioxxterms:id>https://isni.org/isni/0000000110927289</rioxxterms:id>
</rioxxterms:publisher>
<dc:source>1812-0792</dc:source>
<dc:title>Increasing turbidity in the North Sea during the 20th century due to changing wave climate</dc:title>
<dcterms:dateAccepted>2019-10-02</dcterms:dateAccepted>
<rioxxterms:creator
first-named-author="true">
<rioxxterms:name>Wilson, Robert J.</rioxxterms:name>
<rioxxterms:id>https://orcid.org/0000-0002-0592-366X</rioxxterms:id>
</rioxxterms:creator>
<rioxxterms:creator>
<rioxxterms:name>Heath, Michael R.</rioxxterms:name>
<rioxxterms:id>https://orcid.org/0000-0001-6602-3107</rioxxterms:id>
<rioxxterms:id> https://viaf.org/viaf/15147423189944882613</rioxxterms:id>
</rioxxterms:creator>
<rioxxterms:publication_date>2019-12-09</rioxxterms:publication_date>
<rioxxterms:record_public_release_date>2019-10-15</rioxxterms:record_public_release_date>
<dc:type>https://purl.org/coar/resource_type/c_2df8fbb1</dc:type>
<rioxxterms:grant
funder_name="Australian Research Council"
funder_id="https://ror.org/05mmh0f86">
DP190101507
</rioxxterms:grant>
<rioxxterms:grant
funder_name="John Templeton Foundation"
funder_id="https://ror.org/035tnyy05">
61387
</rioxxterms:grant>
<dc:identifier>https://strathprints.strath.ac.uk/70117/</dc:identifier>
<dc:relation
rel="item"
type="application/pdf"
coar_type="https://purl.org/coar/resource_type/c_6501"
coar_version="https://purl.org/coar/version/c_ab4af688f83e57aa"
deposit_date="2019-12-11"
resource_exposed_date="2019-12-11"
access_rights_="https://purl.org/coar/access_right/c_abf2"
license_ref="https://creativecommons.org/licenses/by-nc-nd/4.0/">
https://strathprints.strath.ac.uk/70117/7/Wilson_Heath_OS2019_Increasing_turbidity_in_the_North_Sea_during_the_20th_century.pdf
</dc:relation>
<!-- Other expressions (or 'instances') - publisher version -->
<rioxxterms:ext_relation
rel="cite-as"
coar_type="https://purl.org/coar/resource_type/c_6501"
coar_version="https://purl.org/coar/version/c_970fb48d4fbd8a85">
https://doi.org/10.1007/s11229-020-02724-x
</rioxxterms:ext_relation>
<!-- related dataset -->
<rioxxterms:ext_relation
rel="cite-as"
coar_type="https://purl.org/coar/resource_type/c_ddb1">
https://doi.org/10.15129/5d28213e-8f9f-402a-b550-fc588518cb8b
</rioxxterms:ext_relation >
<!-- related software -->
<rioxxterms:ext_relation
rel="cite-as"
coar_type="https://purl.org/coar/resource_type/QH80-2R4E">
https://doi.org/10.5281/zenodo.3478185
</rioxxterms:ext_relation>
</rioxx>

View File

@@ -0,0 +1,217 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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/
-->
<metadata
xmlns="http://www.lyncode.com/xoai"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.lyncode.com/xoai http://www.lyncode.com/xsd/xoai.xsd">
<element name="dspace">
<element name="entity">
<element name="type">
<element name="none">
<field name="value">Publication</field>
</element>
</element>
</element>
</element>
<element name="dcterms">
<element name="dateAccepted">
<element name="none">
<field name="value">2023-11-07</field>
</element>
</element>
</element>
<element name="dc">
<element name="contributor">
<element name="author">
<element name="none">
<field name="value">Tsigaridis, Konstantinos G.</field>
<field name="authority">virtual::44</field>
<field name="confidence">-1</field>
<field name="value">Wang, Rui</field>
<field name="authority">virtual::46</field>
<field name="confidence">-1</field>
<field name="value">Ellefson, Michelle R.</field>
<field name="authority">virtual::47</field>
<field name="confidence">-1</field>
</element>
</element>
</element>
<element name="date">
<element name="accessioned">
<element name="none">
<field name="value">2023-11-07T11:34:10Z</field>
</element>
</element>
<element name="available">
<element name="none">
<field name="value">2023-11-07T11:34:10Z</field>
</element>
</element>
<element name="issued">
<element name="none">
<field name="value">2022-11-30</field>
</element>
</element>
</element>
<element name="identifier">
<element name="uri">
<element name="none">
<field name="value">https://example.org/handle/1811/160</field>
</element>
</element>
</element>
<element name="language">
<element name="iso">
<element name="none">
<field name="value">eng</field>
</element>
</element>
</element>
<element name="title">
<element name="none">
<field name="value">The Intercorrelation Between Executive Function, Physics Problem Solving, Mathematical, and Matrix Reasoning Skills: Reflections from a Small-Scale Experiment</field>
</element>
</element>
<element name="type">
<element name="none">
<field name="value">Article</field>
</element>
</element>
</element>
<element name="relation">
<element name="isAuthorOfPublication">
<element name="none">
<field name="value">a57363fa-f82e-4684-bd76-f7bc1e893603</field>
<field name="authority">virtual::44</field>
<field name="confidence">-1</field>
<field name="value">e00b3d0d-65e2-4c30-825d-1a4839845790</field>
<field name="authority">virtual::46</field>
<field name="confidence">-1</field>
<field name="value">bdd38a03-206d-4f9b-bafb-70e060ad176f</field>
<field name="authority">virtual::47</field>
<field name="confidence">-1</field>
</element>
<element name="latestForDiscovery">
<element name="none">
<field name="value">a57363fa-f82e-4684-bd76-f7bc1e893603</field>
<field name="authority">virtual::44</field>
<field name="confidence">-1</field>
<field name="value">e00b3d0d-65e2-4c30-825d-1a4839845790</field>
<field name="authority">virtual::46</field>
<field name="confidence">-1</field>
<field name="value">bdd38a03-206d-4f9b-bafb-70e060ad176f</field>
<field name="authority">virtual::47</field>
<field name="confidence">-1</field>
</element>
</element>
</element>
<element name="isJournalOfPublication">
<element name="none">
<field name="value">05a400b1-ff0b-4e40-80cd-a7d1b712ace2</field>
<field name="authority">virtual::71</field>
<field name="confidence">-1</field>
</element>
</element>
<element name="isJournalIssueOfPublication">
<element name="none">
<field name="value">7524a0cf-3ea2-40c7-a265-d583425ed4d7</field>
<field name="authority">virtual::71</field>
<field name="confidence">-1</field>
</element>
<element name="latestForDiscovery">
<element name="none">
<field name="value">7524a0cf-3ea2-40c7-a265-d583425ed4d7</field>
<field name="authority">virtual::71</field>
<field name="confidence">-1</field>
</element>
</element>
</element>
</element>
<element name="person">
<element name="identifier">
<element name="orcid">
<element name="none">
<field name="value">0000-0003-0407-9767</field>
<field name="authority">virtual::47</field>
<field name="confidence">-1</field>
</element>
</element>
</element>
</element>
<element name="creativeworkseries">
<element name="issn">
<element name="none">
<field name="value">2634-9876</field>
<field name="authority">virtual::71</field>
<field name="confidence">-1</field>
</element>
</element>
</element>
<element name="bundles">
<element name="bundle">
<field name="name">ORIGINAL</field>
<element name="bitstreams">
<element name="bitstream">
<field name="name">Tsigaridis et al., 2022.pdf</field>
<field name="format">application/pdf</field>
<field name="size">1554917</field>
<field name="url">https://example.org/bitstreams/9121e795-0af3-4ff3-be2a-4b28418fb269/download</field>
<field name="checksum">42d8cd076931e43e02d0af70a36d704e</field>
<field name="checksumAlgorithm">MD5</field>
<field name="sid">1</field>
<field name="primary">true</field>
<element name="resourcePolicies">
<element name="resourcePolicy">
<field name="group">Anonymous</field>
<field name="user">Anonymous</field>
<field name="action">READ</field>
</element>
</element>
</element>
</element>
</element>
<element name="bundle">
<field name="name">THUMBNAIL</field>
<element name="bitstreams">
<element name="bitstream">
<field name="name">cerj_volume_9_thumbnail.jpg</field>
<field name="format">image/jpeg</field>
<field name="size">14513</field>
<field name="url">https://example.org/bitstreams/16245937-10bb-46db-9817-683a5ebd8d63/download</field>
<field name="checksum">8c39d691daa8e5f9d668668db7910cd6</field>
<field name="checksumAlgorithm">MD5</field>
<field name="sid">2</field>
<field name="primary">false</field>
<element name="resourcePolicies">
<element name="resourcePolicy">
<field name="group">Anonymous</field>
<field name="user">Anonymous</field>
<field name="action">READ</field>
</element>
</element>
</element>
</element>
</element>
</element>
<element name="others">
<field name="handle">1811/160</field>
<field name="identifier">oai:example.org:1811/160</field>
<field name="lastModifyDate">2023-12-13 13:07:56.51</field>
<element name="access-status">
<field name="value">open.access</field>
</element>
</element>
<element name="repository">
<field name="url">https://example.org</field>
<field name="name">Diamond DSpace (dev)</field>
<field name="mail">support@example.org</field>
</element>
<element name="license"/>
</metadata>

View File

@@ -1,194 +0,0 @@
#DSpace REST API (Jersey) - DEPRECATED
A RESTful web services API for DSpace, built using JAX-RS1 JERSEY.
_This REST API has been deprecated and will be removed in v8. Please use the Server API (/server) webapp instead._
##Getting Started
This REST API is integrated directly into the DSpace codebase.
* Rebuild as usual: mvn + ant
* Deploy the webapp (i.e to Tomcat)
* ```<Context path="/rest" docBase="/dspace/webapps/rest" />```
REST API can do all CRUD (create, read, update, delete) operations over communities, collections, items, bitstream and bitstream policies. Without logging into the REST API, you have read access as an anonymous user (member of the Anonymous group). If you want to make changes in DSpace using the REST API, you must log into the API using the "login" endpoint and then use the returned token in request header of your subsequent API calls.
##Endpoints
| Resource |CREATE|READ list|READ single|Edit|Delete|Search|
| ------------- |------|:-------:|-----------|----|------|------|
| /communities | Y | Y | Y | Y | Y | |
| /collections | Y | Y | Y | Y | Y | Y |
| /items | Y | Y | Y | Y | Y | Y |
| /bitstreams | Y | Y | Y | Y | Y | ||
Search in collections is possible only by name and search in items only by metadata field.
###Index
Get information on how to use the API
- GET http://localhost:8080
Test whether the REST API is running and available
- GET http://localhost:8080/rest/test
Log into REST API
- POST http://localhost:8080/rest/login
Logout from REST API
- POST http://localhost:8080/rest/logout
Get status of REST API and the logged-in user
- GET http://localhost:8080/rest/status
###Communities
View the list of top-level communities
- GET http://localhost:8080/rest/communities/top-communities
View the list of all communities
- GET http://localhost:8080/rest/communities[?expand={collections,parentCommunity,subCommunities,logo,all}]
View a specific community
- GET http://localhost:8080/rest/communities/:ID[?expand={collections,parentCommunity,subCommunities,logo,all}]
View the list of subcollections in community
- GET http://localhost:8080/rest/communities/:ID/collections[?expand={items,parentCommunityList,license,logo,all}]
View the list of subcommunities in community
- GET http://localhost:8080/rest/communities/:ID/communities[?expand={collections,parentCommunity,subCommunities,logo,all}]
Create new top-level community
- POST http://localhost:8080/rest/communities
Create new subcollection in community
- POST http://localhost:8080/rest/communities/:ID/collections
Create new subcommunity in community
- POST http://localhost:8080/rest/communities/:ID/communities
Update community
- PUT http://localhost:8080/rest/communities/:ID
Delete community
- DELETE http://localhost:8080/rest/communities/:ID
Delete subcollection in community
- DELETE http://localhost:8080/rest/communities/:ID/collections/:ID
Delete subcommunity in community
- DELETE http://localhost:8080/rest/communities/:ID/communities/:ID
###Collections
View the list of collections
- GET http://localhost:8080/rest/collections[?expand={items,parentCommunityList,license,logo,all}]
View a specific collection
- GET http://localhost:8080/rest/collections/:ID[?expand={items,parentCommunityList,license,logo,all}]
View items in collection
- GET http://localhost:8080/rest/collections/:ID/items[?expand={metadata,parentCollection,parentcollectionList,parentCommunityList,bitstreams,all}]
Create item in collection
- POST http://localhost:8080/rest/collections/:ID/items
Find collection by name
- POST http://localhost:8080/rest/collections/find-collection
Update collection
- PUT http://localhost:8080/rest/collections/:ID
Delete collection
- DELETE http://localhost:8080/rest/collections/:ID
Delete item in collection
- DELETE http://localhost:8080/rest/collections/:ID/items/:ID
###Items
View the list of items
- GET http://localhost:8080/rest/items[?expand={metadata,parentCollection,parentcollectionList,parentCommunityList,bitstreams,all}]
View speciific item
- GET http://localhost:8080/rest/items/:ID[?expand={metadata,parentCollection,parentcollectionList,parentCommunityList,bitstreams,all}]
View an Item and view its bitstreams
- GET http://localhost:8080/rest/items/:ID/bitstreams[?expand={parent,policies,all}]
View an Item, and view its metadata
- GET http://localhost:8080/rest/items/:ID/metadata
Find item by metadata
- POST http://localhost:8080/rest/items/find-by-metadata-field
Add metadata to item
- POST http://localhost:8080/rest/items/:ID/metadata
Create bitstream in item
- POST http://localhost:8080/rest/items/:ID/bitstreams
Update metadata in item
- PUT http://localhost:8080/rest/items/:ID/metadata
Delete item
- DELETE http://localhost:8080/rest/items/:ID
Delete all metadata in item
- DELETE http://localhost:8080/rest/items/:ID/metadata
Delete bitstream in item
- DELETE http://localhost:8080/rest/items/:ID/bitstreams/:ID
###Bitstreams
View the list of bitstreams
- GET http://localhost:8080/rest/bitstreams[?expand={parent,policies,all}]
View information about a bitstream
- GET http://localhost:8080/rest/bitstreams/:ID[?expand={parent,policies,all}]
View/Download a specific Bitstream
- GET http://localhost:8080/rest/bitstreams/:ID/retrieve
View the list of policies of bitstream
- GET http://localhost:8080/rest/bitstreams/:ID/policy
Add policy to bitstream
- POST http://localhost:8080/rest/bitstreams/:ID/policy
Update bitstream
- PUT http://localhost:8080/rest/bitstreams/:ID
Update data of bitstream
- PUT http://localhost:8080/rest/bitstreams/:ID/data
Delete bitstream
- DELETE http://localhost:8080/rest/bitstreams/:ID
Delete policy of bitstream
- DELETE http://localhost:8080/rest/bitstreams/:ID/policy/:ID
####Statistics
Recording view events of items and download events of bitstreams (set stats = true in rest.cfg to enable recording of events)
http://localhost:8080/rest/items/:ID?userIP=ip&userAgent=userAgent&xforwardedfor=xforwardedfor
If no parameters are given, the details of the HTTP request sender are used in statistics.
This enables tools like proxies to supply the details of their user rather than themselves.
###Handles
Lookup a DSpaceObject by its Handle, this produces the name/ID that you look up in /bitstreams, /items, /collections, /communities
- http://localhost:8080/rest/handle/{prefix}/{suffix}
##Expand
There is an ?expand= query parameter for more expensive operations. You can add it at the end of the request URL.
It is optional, all, some or none. The response will usually indicate what the available "expand" options are.
##HTTP Responses
* 200 OK - The requested object/objects exists
* 401 Unauthorized - The anonymous user does not have READ access to that object
* 404 Not Found - The specified object doesn't exist
* 405 Method Not Allowed - Wrong request method (GET,POST,PUT,DELETE) or wrong data format (JSON/XML).
* 415 Unsupported Media Type - Missing "Content-Type: application/json" or "Content-Type: application/xml" request header
* 500 Server Error - Likely a SQLException, IOException, more details in the logs.

View File

@@ -1,202 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.dspace</groupId>
<artifactId>dspace-rest</artifactId>
<packaging>war</packaging>
<version>8.0-SNAPSHOT</version>
<name>DSpace (Deprecated) REST Webapp</name>
<description>DSpace RESTful Web Services API. NOTE: this REST API is DEPRECATED.
Please consider using the REST API in the dspace-server-webapp instead!</description>
<url>http://demo.dspace.org</url>
<parent>
<groupId>org.dspace</groupId>
<artifactId>dspace-parent</artifactId>
<version>8.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<properties>
<!-- This is the path to the root [dspace-src] directory. -->
<root.basedir>${basedir}/..</root.basedir>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<attachClasses>true</attachClasses>
<!-- Filter the web.xml (needed for IDE compatibility/debugging) -->
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
</configuration>
</plugin>
<plugin>
<groupId>com.mycila</groupId>
<artifactId>license-maven-plugin</artifactId>
<configuration>
<!--Exclude license check for third-party files which don't need it-->
<excludes>
<exclude>**/static/reports/spin.js</exclude>
<exclude>**/static/reports/README.md</exclude>
<exclude>**/*.xsd</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Jersey, for RESTful web services -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-jaxb</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- Spring dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- Jersey + Spring -->
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring5</artifactId>
<version>${jersey.version}</version>
<exclusions>
<!-- We provide our own version of Spring framework dependencies -->
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</exclusion>
<!-- Newer version provided by jersey-server above -->
<exclusion>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring-security.version}</version>
<exclusions>
<!-- Latest version will be provided by spring-context-->
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring-security.version}</version>
<exclusions>
<!-- Latest version will be provided by spring-context-->
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-api</artifactId>
</dependency>
<!-- Connecting to DSpace datasource sets a dependency on Postgres DB-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.atteo</groupId>
<artifactId>evo-inflector</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-services</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@@ -1,783 +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.rest;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLConnection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.authorize.service.ResourcePolicyService;
import org.dspace.content.BitstreamFormat;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.BundleService;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.GroupService;
import org.dspace.rest.common.Bitstream;
import org.dspace.rest.common.ResourcePolicy;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.storage.bitstore.factory.StorageServiceFactory;
import org.dspace.storage.bitstore.service.BitstreamStorageService;
import org.dspace.usage.UsageEvent;
/**
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*/
// Every DSpace class used without namespace is from package
// org.dspace.rest.common.*. Otherwise namespace is defined.
@Path("/bitstreams")
public class BitstreamResource extends Resource {
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory.getInstance()
.getBitstreamFormatService();
protected BitstreamStorageService bitstreamStorageService = StorageServiceFactory.getInstance()
.getBitstreamStorageService();
protected ResourcePolicyService resourcePolicyService = AuthorizeServiceFactory.getInstance()
.getResourcePolicyService();
protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(BitstreamResource.class);
/**
* Return bitstream properties without file data. It can throw
* WebApplicationException with three response codes. Response code
* NOT_FOUND(404) or UNAUTHORIZED(401) or INTERNAL_SERVER_ERROR(500). Bad
* request is when the bitstream id does not exist. UNAUTHORIZED if the user
* logged into the DSpace context does not have the permission to access the
* bitstream. Server error when something went wrong.
*
* @param bitstreamId Id of bitstream in DSpace.
* @param expand This string defines which additional optional fields will be added
* to bitstream response. Individual options are separated by commas without
* spaces. The options are: "all", "parent".
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the item as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return If user is allowed to read bitstream, it returns instance of
* bitstream. Otherwise, it throws WebApplicationException with
* response code UNAUTHORIZED.
* @throws WebApplicationException It can happen on: Bad request, unauthorized, SQL exception
* and context exception(could not create context).
*/
@GET
@Path("/{bitstream_id}")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Bitstream getBitstream(@PathParam("bitstream_id") String bitstreamId, @QueryParam("expand") String expand,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading bitstream(id=" + bitstreamId + ") metadata.");
org.dspace.core.Context context = null;
Bitstream bitstream = null;
try {
context = createContext();
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId,
org.dspace.core.Constants.READ);
writeStats(dspaceBitstream, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers,
request, context);
bitstream = new Bitstream(dspaceBitstream, servletContext, expand, context);
context.complete();
log.trace("Bitstream(id=" + bitstreamId + ") was successfully read.");
} catch (SQLException e) {
processException(
"Someting went wrong while reading bitstream(id=" + bitstreamId + ") from database! Message: " + e,
context);
} catch (ContextException e) {
processException(
"Someting went wrong while reading bitstream(id=" + bitstreamId + "), ContextException. Message: "
+ e.getMessage(), context);
} finally {
processFinally(context);
}
return bitstream;
}
/**
* Return all bitstream resource policies from all bundles, in which
* the bitstream is present.
*
* @param bitstreamId Id of bitstream in DSpace.
* @param headers If you want to access the item as the user logged into the context.
* The header "rest-dspace-token" with the token passed
* from the login method must be set.
* @return Returns an array of ResourcePolicy objects.
*/
@GET
@Path("/{bitstream_id}/policy")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public ResourcePolicy[] getBitstreamPolicies(@PathParam("bitstream_id") String bitstreamId,
@Context HttpHeaders headers) {
log.info("Reading bitstream(id=" + bitstreamId + ") policies.");
org.dspace.core.Context context = null;
ResourcePolicy[] policies = null;
try {
context = createContext();
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId,
org.dspace.core.Constants.READ);
policies = new Bitstream(dspaceBitstream, servletContext, "policies", context).getPolicies();
context.complete();
log.trace("Policies for bitstream(id=" + bitstreamId + ") was successfully read.");
} catch (SQLException e) {
processException("Someting went wrong while reading policies of bitstream(id=" + bitstreamId
+ "), SQLException! Message: " + e, context);
} catch (ContextException e) {
processException("Someting went wrong while reading policies of bitstream(id=" + bitstreamId
+ "), ContextException. Message: " + e.getMessage(), context);
} finally {
processFinally(context);
}
return policies;
}
/**
* Read list of bitstreams. It throws WebApplicationException with response
* code INTERNAL_SERVER_ERROR(500), if there was problem while reading
* bitstreams from database.
*
* @param expand This string defines which additional optional fields will be added
* to bitstream response. Individual options are separated by commas without
* spaces. The options are: "all", "parent".
* @param limit How many bitstreams will be in the list. Default value is 100.
* @param offset On which offset (item) the list starts. Default value is 0.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the item as the user logged into the context.
* The header "rest-dspace-token" with the token passed
* from the login method must be set.
* @param request Servlet's HTTP request object.
* @return Returns an array of bistreams. Array doesn't contain bitstreams for
* which the user doesn't have read permission.
* @throws WebApplicationException Thrown in case of a problem with reading the database or with
* creating a context.
*/
@GET
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Bitstream[] getBitstreams(@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("100") Integer limit,
@QueryParam("offset") @DefaultValue("0") Integer offset,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading bitstreams.(offset=" + offset + ",limit=" + limit + ")");
org.dspace.core.Context context = null;
List<Bitstream> bitstreams = new ArrayList<Bitstream>();
try {
context = createContext();
List<org.dspace.content.Bitstream> dspaceBitstreams = bitstreamService.findAll(context);
if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) {
log.warn("Paging was badly set.");
limit = 100;
offset = 0;
}
// TODO If bitstream doesn't exist, throws exception.
for (int i = offset; (i < (offset + limit)) && (i < dspaceBitstreams.size()); i++) {
if (authorizeService
.authorizeActionBoolean(context, dspaceBitstreams.get(i), org.dspace.core.Constants.READ)) {
if (bitstreamService.getParentObject(context, dspaceBitstreams
.get(i)) != null) { // To eliminate bitstreams which cause exception, because of
// reading under administrator permissions
bitstreams.add(new Bitstream(dspaceBitstreams.get(i), servletContext, expand, context));
writeStats(dspaceBitstreams.get(i), UsageEvent.Action.VIEW, user_ip, user_agent,
xforwardedfor, headers, request, context);
}
}
}
context.complete();
log.trace("Bitstreams were successfully read.");
} catch (SQLException e) {
processException("Something went wrong while reading bitstreams from database!. Message: " + e, context);
} catch (ContextException e) {
processException(
"Something went wrong while reading bitstreams, ContextException. Message: " + e.getMessage(),
context);
} finally {
processFinally(context);
}
return bitstreams.toArray(new Bitstream[0]);
}
/**
* Read bitstream data. May throw WebApplicationException with the
* INTERNAL_SERVER_ERROR(500) code. Caused by three exceptions: IOException if
* there was a problem with reading bitstream file. SQLException if there was
* a problem while reading from database. And AuthorizeException if there was
* a problem with authorization of user logged to DSpace context.
*
* @param bitstreamId Id of the bitstream, whose data will be read.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the item as the user logged into the context.
* The header "rest-dspace-token" with the token passed
* from the login method must be set.
* @param request Servlet's HTTP request object.
* @return Returns response with data with file content type. It can
* return the NOT_FOUND(404) response code in case of wrong bitstream
* id. Or response code UNAUTHORIZED(401) if user is not
* allowed to read bitstream.
* @throws WebApplicationException Thrown if there was a problem: reading the file data; or reading
* the database; or creating the context; or with authorization.
*/
@GET
@Path("/{bitstream_id}/retrieve")
public javax.ws.rs.core.Response getBitstreamData(@PathParam("bitstream_id") String bitstreamId,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading data of bitstream(id=" + bitstreamId + ").");
org.dspace.core.Context context = null;
InputStream inputStream = null;
String type = null;
String name = null;
try {
context = createContext();
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId,
org.dspace.core.Constants.READ);
writeStats(dspaceBitstream, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor, headers,
request, context);
log.trace("Bitstream(id=" + bitstreamId + ") data was successfully read.");
inputStream = bitstreamService.retrieve(context, dspaceBitstream);
type = dspaceBitstream.getFormat(context).getMIMEType();
name = dspaceBitstream.getName();
context.complete();
} catch (IOException e) {
processException("Could not read file of bitstream(id=" + bitstreamId + ")! Message: " + e, context);
} catch (SQLException e) {
processException(
"Something went wrong while reading bitstream(id=" + bitstreamId + ") from database! Message: " + e,
context);
} catch (AuthorizeException e) {
processException(
"Could not retrieve file of bitstream(id=" + bitstreamId + "), AuthorizeException! Message: " + e,
context);
} catch (ContextException e) {
processException(
"Could not retrieve file of bitstream(id=" + bitstreamId + "), ContextException! Message: " + e
.getMessage(),
context);
} finally {
processFinally(context);
}
return Response.ok(inputStream).type(type)
.header("Content-Disposition", "attachment; filename=\"" + name + "\"")
.build();
}
/**
* Add bitstream policy to all bundles containing the bitstream.
*
* @param bitstreamId Id of bitstream in DSpace.
* @param policy Policy to be added. The following attributes are not
* applied: epersonId,
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the item as the user logged into the context.
* The header "rest-dspace-token" with the token passed
* from the login method must be set.
* @param request Servlet's HTTP request object.
* @return Returns ok, if all was ok. Otherwise status code 500.
*/
@POST
@Path("/{bitstream_id}/policy")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public javax.ws.rs.core.Response addBitstreamPolicy(@PathParam("bitstream_id") String bitstreamId,
ResourcePolicy policy,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Adding bitstream(id=" + bitstreamId + ") " + policy
.getAction() + " policy with permission for group(id=" + policy.getGroupId()
+ ").");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId,
org.dspace.core.Constants.WRITE);
writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers,
request, context);
addPolicyToBitstream(context, policy, dspaceBitstream);
context.complete();
log.trace("Policy for bitstream(id=" + bitstreamId + ") was successfully added.");
} catch (SQLException e) {
processException("Someting went wrong while adding policy to bitstream(id=" + bitstreamId
+ "), SQLException! Message: " + e, context);
} catch (ContextException e) {
processException("Someting went wrong while adding policy to bitstream(id=" + bitstreamId
+ "), ContextException. Message: " + e.getMessage(), context);
} catch (AuthorizeException e) {
processException("Someting went wrong while adding policy to bitstream(id=" + bitstreamId
+ "), AuthorizeException! Message: " + e, context);
} finally {
processFinally(context);
}
return Response.status(Status.OK).build();
}
/**
* Update bitstream metadata. Replaces everything on targeted bitstream.
* May throw WebApplicationException caused by two exceptions:
* SQLException, if there was a problem with the database. AuthorizeException if
* there was a problem with the authorization to edit bitstream metadata.
*
* @param bitstreamId Id of bistream to be updated.
* @param bitstream Bitstream with will be placed. It must have filled user
* credentials.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the item as the user logged into the context.
* The header "rest-dspace-token" with the token passed
* from the login method must be set.
* @param request Servlet's HTTP request object.
* @return Return response codes: OK(200), NOT_FOUND(404) if bitstream does
* not exist and UNAUTHORIZED(401) if user is not allowed to write
* to bitstream.
* @throws WebApplicationException Thrown when: Error reading from database; or error
* creating context; or error regarding bitstream authorization.
*/
@PUT
@Path("/{bitstream_id}")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response updateBitstream(@PathParam("bitstream_id") String bitstreamId, Bitstream bitstream,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Updating bitstream(id=" + bitstreamId + ") metadata.");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId,
org.dspace.core.Constants.WRITE);
writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor,
headers, request, context);
log.trace("Updating bitstream metadata.");
dspaceBitstream.setDescription(context, bitstream.getDescription());
if (getMimeType(bitstream.getName()) == null) {
BitstreamFormat unknownFormat = bitstreamFormatService.findUnknown(context);
bitstreamService.setFormat(context, dspaceBitstream, unknownFormat);
} else {
BitstreamFormat guessedFormat = bitstreamFormatService
.findByMIMEType(context, getMimeType(bitstream.getName()));
bitstreamService.setFormat(context, dspaceBitstream, guessedFormat);
}
dspaceBitstream.setName(context, bitstream.getName());
Integer sequenceId = bitstream.getSequenceId();
if (sequenceId != null && sequenceId.intValue() != -1) {
dspaceBitstream.setSequenceID(sequenceId);
}
bitstreamService.update(context, dspaceBitstream);
if (bitstream.getPolicies() != null) {
log.trace("Updating bitstream policies.");
// Remove all old bitstream policies.
authorizeService.removeAllPolicies(context, dspaceBitstream);
// Add all new bitstream policies
for (ResourcePolicy policy : bitstream.getPolicies()) {
addPolicyToBitstream(context, policy, dspaceBitstream);
}
}
context.complete();
} catch (SQLException e) {
processException("Could not update bitstream(id=" + bitstreamId + ") metadata, SQLException. Message: " + e,
context);
} catch (AuthorizeException e) {
processException(
"Could not update bitstream(id=" + bitstreamId + ") metadata, AuthorizeException. Message: " + e,
context);
} catch (ContextException e) {
processException(
"Could not update bitstream(id=" + bitstreamId + ") metadata, ContextException. Message: " + e
.getMessage(),
context);
} finally {
processFinally(context);
}
log.info("Bitstream metadata(id=" + bitstreamId + ") were successfully updated.");
return Response.ok().build();
}
/**
* Update bitstream data. Changes bitstream data by editing database rows.
* May throw WebApplicationException caused by: SQLException if there was
* a problem editing or reading the database, IOException if there was
* a problem with reading from InputStream, Exception if there was another
* problem.
*
* @param bitstreamId Id of bistream to be updated.
* @param is InputStream filled with new data.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the item as the user logged into the context.
* The header "rest-dspace-token" with the token passed
* from the login method must be set.
* @param request Servlet's HTTP request object.
* @return Return response if bitstream was updated. Response codes:
* OK(200), NOT_FOUND(404) if id of bitstream was bad. And
* UNAUTHORIZED(401) if user is not allowed to update bitstream.
* @throws WebApplicationException This exception can be thrown in this cases: Problem with
* reading or writing to database. Or problem with reading from
* InputStream.
*/
// TODO Change to better logic, without editing database.
@PUT
@Path("/{bitstream_id}/data")
public Response updateBitstreamData(@PathParam("bitstream_id") String bitstreamId, InputStream is,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Updating bitstream(id=" + bitstreamId + ") data.");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId,
org.dspace.core.Constants.WRITE);
writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor,
headers, request, context);
log.trace("Creating new bitstream.");
UUID newBitstreamId = bitstreamStorageService.store(context, dspaceBitstream, is);
log.trace("Bitstream data stored: " + newBitstreamId);
context.complete();
} catch (SQLException e) {
processException("Could not update bitstream(id=" + bitstreamId + ") data, SQLException. Message: " + e,
context);
} catch (IOException e) {
processException("Could not update bitstream(id=" + bitstreamId + ") data, IOException. Message: " + e,
context);
} catch (ContextException e) {
processException(
"Could not update bitstream(id=" + bitstreamId + ") data, ContextException. Message: " + e.getMessage(),
context);
} finally {
processFinally(context);
}
log.info("Bitstream(id=" + bitstreamId + ") data was successfully updated.");
return Response.ok().build();
}
/**
* Delete bitstream from all bundles in DSpace. May throw
* WebApplicationException, which can be caused by three exceptions.
* SQLException if there was a problem reading from database or removing
* from database. AuthorizeException, if user doesn't have permission to delete
* the bitstream or file. IOException, if there was a problem deleting the file.
*
* @param bitstreamId Id of bitstream to be deleted.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the item as the user logged into the context.
* The header "rest-dspace-token" with the token passed
* from the login method must be set.
* @param request Servlet's HTTP request object.
* @return Return response codes: OK(200), NOT_FOUND(404) if bitstream of
* that id does not exist and UNAUTHORIZED(401) if user is not
* allowed to delete bitstream.
* @throws WebApplicationException Can be thrown if there was a problem reading or editing
* the database. Or problem deleting the file. Or problem with
* authorization to bitstream and bundles. Or problem with
* creating context.
*/
@DELETE
@Path("/{bitstream_id}")
public Response deleteBitstream(@PathParam("bitstream_id") String bitstreamId, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Deleting bitstream(id=" + bitstreamId + ").");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId,
org.dspace.core.Constants.DELETE);
writeStats(dspaceBitstream, UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor,
headers, request, context);
log.trace("Deleting bitstream from all bundles.");
bitstreamService.delete(context, dspaceBitstream);
context.complete();
} catch (SQLException e) {
processException("Could not delete bitstream(id=" + bitstreamId + "), SQLException. Message: " + e,
context);
} catch (AuthorizeException e) {
processException("Could not delete bitstream(id=" + bitstreamId + "), AuthorizeException. Message: " + e,
context);
} catch (IOException e) {
processException("Could not delete bitstream(id=" + bitstreamId + "), IOException. Message: " + e, context);
} catch (ContextException e) {
processException(
"Could not delete bitstream(id=" + bitstreamId + "), ContextException. Message:" + e.getMessage(),
context);
} finally {
processFinally(context);
}
log.info("Bitstream(id=" + bitstreamId + ") was successfully deleted.");
return Response.ok().build();
}
/**
* Delete policy.
*
* @param bitstreamId Id of the DSpace bitstream whose policy will be deleted.
* @param policyId Id of the policy to delete.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the item as the user logged into the context.
* The header "rest-dspace-token" with the token passed
* from the login method must be set.
* @param request Servlet's HTTP request object.
* @return It returns Ok, if all was ok. Otherwise status code 500.
*/
@DELETE
@Path("/{bitstream_id}/policy/{policy_id}")
public javax.ws.rs.core.Response deleteBitstreamPolicy(@PathParam("bitstream_id") String bitstreamId,
@PathParam("policy_id") Integer policyId,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Deleting policy(id=" + policyId + ") from bitstream(id=" + bitstreamId + ").");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.Bitstream dspaceBitstream = findBitstream(context, bitstreamId,
org.dspace.core.Constants.WRITE);
writeStats(dspaceBitstream, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor, headers,
request, context);
org.dspace.authorize.ResourcePolicy resourcePolicy = resourcePolicyService.find(context, policyId);
if (resourcePolicy.getdSpaceObject().getID().equals(dspaceBitstream.getID()) && authorizeService
.authorizeActionBoolean(context, dspaceBitstream, org.dspace.core.Constants.REMOVE)) {
try {
resourcePolicyService.delete(context, resourcePolicy);
} catch (AuthorizeException e) {
processException(
"Someting went wrong while deleting policy(id=" + policyId + ") to bitstream(id=" + bitstreamId
+ "), AuthorizeException! Message: " + e, context);
}
log.trace("Policy for bitstream(id=" + bitstreamId + ") was successfully removed.");
}
context.complete();
} catch (SQLException e) {
processException(
"Someting went wrong while deleting policy(id=" + policyId + ") to bitstream(id=" + bitstreamId
+ "), SQLException! Message: " + e, context);
} catch (ContextException e) {
processException(
"Someting went wrong while deleting policy(id=" + policyId + ") to bitstream(id=" + bitstreamId
+ "), ContextException. Message: " + e.getMessage(), context);
} finally {
processFinally(context);
}
return Response.status(Status.OK).build();
}
/**
* Return the MIME type of the file, by file extension.
*
* @param name Name of file.
* @return String filled with type of file in MIME style.
*/
static String getMimeType(String name) {
return URLConnection.guessContentTypeFromName(name);
}
/**
* Add policy(org.dspace.rest.common.ResourcePolicy) to bitstream.
*
* @param context Context to create DSpace ResourcePolicy.
* @param policy Policy which will be added to bitstream.
* @param dspaceBitstream DSpace Bitstream object.
* @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.
*/
private void addPolicyToBitstream(org.dspace.core.Context context, ResourcePolicy policy,
org.dspace.content.Bitstream dspaceBitstream)
throws SQLException, AuthorizeException {
org.dspace.authorize.ResourcePolicy dspacePolicy = resourcePolicyService.create(context);
dspacePolicy.setAction(policy.getActionInt());
dspacePolicy.setGroup(groupService.findByIdOrLegacyId(context, policy.getGroupId()));
dspacePolicy.setdSpaceObject(dspaceBitstream);
dspacePolicy.setStartDate(policy.getStartDate());
dspacePolicy.setEndDate(policy.getEndDate());
dspacePolicy.setRpDescription(policy.getRpDescription());
dspacePolicy.setRpName(policy.getRpName());
resourcePolicyService.update(context, dspacePolicy);
}
/**
* Find bitstream from DSpace database. This encapsulates the
* org.dspace.content.Bitstream.find method with a check whether the item exists and
* whether the user logged into the context has permission to preform the requested action.
*
* @param context Context of actual logged user.
* @param id Id of bitstream in DSpace.
* @param action Constant from org.dspace.core.Constants.
* @return Returns DSpace bitstream.
* @throws WebApplicationException Is thrown when item with passed id is not exists and if user
* has no permission to do passed action.
*/
private org.dspace.content.Bitstream findBitstream(org.dspace.core.Context context, String id, int action)
throws WebApplicationException {
org.dspace.content.Bitstream bitstream = null;
try {
bitstream = bitstreamService.findByIdOrLegacyId(context, id);
if ((bitstream == null) || (bitstreamService.getParentObject(context, bitstream) == null)) {
context.abort();
log.warn("Bitstream(id=" + id + ") was not found!");
throw new WebApplicationException(Response.Status.NOT_FOUND);
} else if (!authorizeService.authorizeActionBoolean(context, bitstream, action)) {
context.abort();
if (context.getCurrentUser() != null) {
log.error("User(" + context.getCurrentUser().getEmail() + ") doesn't have the permission to "
+ getActionString(action) + " bitstream!");
} else {
log.error(
"User(anonymous) doesn't have the permission to " + getActionString(action) + " bitsteam!");
}
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
} catch (SQLException e) {
processException("Something went wrong while finding bitstream. SQLException, Message:" + e, context);
}
return bitstream;
}
}

View File

@@ -1,755 +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.rest;
import static org.dspace.content.service.DSpaceObjectService.MD_COPYRIGHT_TEXT;
import static org.dspace.content.service.DSpaceObjectService.MD_INTRODUCTORY_TEXT;
import static org.dspace.content.service.DSpaceObjectService.MD_LICENSE;
import static org.dspace.content.service.DSpaceObjectService.MD_NAME;
import static org.dspace.content.service.DSpaceObjectService.MD_SHORT_DESCRIPTION;
import static org.dspace.content.service.DSpaceObjectService.MD_SIDEBAR_TEXT;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.Constants;
import org.dspace.core.LogHelper;
import org.dspace.rest.common.Collection;
import org.dspace.rest.common.Item;
import org.dspace.rest.common.MetadataEntry;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.usage.UsageEvent;
import org.dspace.workflow.WorkflowService;
import org.dspace.workflow.factory.WorkflowServiceFactory;
/**
* This class provides all CRUD operation over collections.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*/
@Path("/collections")
public class CollectionsResource extends Resource {
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
protected WorkflowService workflowService = WorkflowServiceFactory.getInstance().getWorkflowService();
private static final Logger log = org.apache.logging.log4j.LogManager.getLogger(CollectionsResource.class);
/**
* Return instance of collection with passed id. You can add more properties
* through expand parameter.
*
* @param collectionId Id of collection in DSpace.
* @param expand String in which is what you want to add to returned instance
* of collection. Options are: "all", "parentCommunityList",
* "parentCommunity", "items", "license" and "logo". If you want
* to use multiple options, it must be separated by commas.
* @param limit Limit value for items in list in collection. Default value is
* 100.
* @param offset Offset of start index in list of items of collection. Default
* value is 0.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return instance of collection. It can also return status code
* NOT_FOUND(404) if id of collection is incorrect or status code
* UNATHORIZED(401) if user has no permission to read collection.
* @throws WebApplicationException It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException). It is thrown by NOT_FOUND and
* UNATHORIZED status codes, too.
*/
@GET
@Path("/{collection_id}")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public org.dspace.rest.common.Collection getCollection(@PathParam("collection_id") String collectionId,
@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("100") Integer limit,
@QueryParam("offset") @DefaultValue("0") Integer offset,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading collection(id=" + collectionId + ").");
org.dspace.core.Context context = null;
Collection collection = null;
try {
context = createContext();
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId,
org.dspace.core.Constants.READ);
writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor,
headers, request, context);
collection = new Collection(dspaceCollection, servletContext, expand, context, limit, offset);
context.complete();
} catch (SQLException e) {
processException("Could not read collection(id=" + collectionId + "), SQLException. Message: " + e,
context);
} catch (ContextException e) {
processException(
"Could not read collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(),
context);
} finally {
processFinally(context);
}
log.trace("Collection(id=" + collectionId + ") has been successfully read.");
return collection;
}
/**
* Return array of all collections in DSpace. You can add more properties
* through expand parameter.
*
* @param expand String in which is what you want to add to returned instance
* of collection. Options are: "all", "parentCommunityList",
* "parentCommunity", "items", "license" and "logo". If you want
* to use multiple options, it must be separated by commas.
* @param limit Limit value for items in list in collection. Default value is
* 100.
* @param offset Offset of start index in list of items of collection. Default
* value is 0.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the collections as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return array of collection, on which has logged user permission
* to view.
* @throws WebApplicationException It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException).
*/
@GET
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public org.dspace.rest.common.Collection[] getCollections(@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("100") Integer limit,
@QueryParam("offset") @DefaultValue("0") Integer offset,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading all collections.(offset=" + offset + ",limit=" + limit + ")");
org.dspace.core.Context context = null;
List<Collection> collections = new ArrayList<>();
try {
context = createContext();
if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) {
log.warn("Paging was badly set.");
limit = 100;
offset = 0;
}
List<org.dspace.content.Collection> dspaceCollections = collectionService.findAll(context, limit, offset);
for (org.dspace.content.Collection dspaceCollection : dspaceCollections) {
if (authorizeService
.authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ)) {
Collection collection = new org.dspace.rest.common.Collection(dspaceCollection, servletContext,
null, context, limit,
offset);
collections.add(collection);
writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent,
xforwardedfor, headers, request, context);
}
}
context.complete();
} catch (SQLException e) {
processException("Something went wrong while reading collections from database. Message: " + e, context);
} catch (ContextException e) {
processException("Something went wrong while reading collections, ContextError. Message: " + e.getMessage(),
context);
} finally {
processFinally(context);
}
log.trace("All collections were successfully read.");
return collections.toArray(new org.dspace.rest.common.Collection[0]);
}
/**
* Return array of items in collection. You can add more properties to items
* with expand parameter.
*
* @param collectionId Id of collection in DSpace.
* @param expand String which define, what additional properties will be in
* returned item. Options are separeted by commas and are: "all",
* "metadata", "parentCollection", "parentCollectionList",
* "parentCommunityList" and "bitstreams".
* @param limit Limit value for items in array. Default value is 100.
* @param offset Offset of start index in array of items of collection. Default
* value is 0.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return array of items, on which has logged user permission to
* read. It can also return status code NOT_FOUND(404) if id of
* collection is incorrect or status code UNATHORIZED(401) if user
* has no permission to read collection.
* @throws WebApplicationException It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException). It is thrown by NOT_FOUND and
* UNATHORIZED status codes, too.
*/
@GET
@Path("/{collection_id}/items")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public org.dspace.rest.common.Item[] getCollectionItems(@PathParam("collection_id") String collectionId,
@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("100") Integer limit,
@QueryParam("offset") @DefaultValue("0") Integer offset,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading collection(id=" + collectionId + ") items.");
org.dspace.core.Context context = null;
List<Item> items = null;
try {
context = createContext();
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId,
org.dspace.core.Constants.READ);
writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor,
headers, request, context);
items = new ArrayList<>();
Iterator<org.dspace.content.Item> dspaceItems = itemService.findByCollection(context, dspaceCollection,
limit, offset);
while (dspaceItems.hasNext()) {
org.dspace.content.Item dspaceItem = dspaceItems.next();
if (itemService.isItemListedForUser(context, dspaceItem)) {
items.add(new Item(dspaceItem, servletContext, expand, context));
writeStats(dspaceItem, UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor,
headers, request, context);
}
}
context.complete();
} catch (SQLException e) {
processException("Could not read collection items, SQLException. Message: " + e, context);
} catch (ContextException e) {
processException("Could not read collection items, ContextException. Message: " + e.getMessage(), context);
} finally {
processFinally(context);
}
log.trace("All items in collection(id=" + collectionId + ") were successfully read.");
return items.toArray(new Item[0]);
}
/**
* Create item in collection. Item can be without filled metadata.
*
* @param collectionId Id of collection in which will be item created.
* @param item Item filled only with metadata, other variables are ignored.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return status code with item. Return status (OK)200 if item was
* created. NOT_FOUND(404) if id of collection does not exists.
* UNAUTHORIZED(401) if user have not permission to write items in
* collection.
* @throws WebApplicationException It is thrown when was problem with database reading or
* writing (SQLException) or problem with creating
* context(ContextException) or problem with authorization to
* collection or IOException or problem with index item into
* browse index. It is thrown by NOT_FOUND and UNATHORIZED
* status codes, too.
*/
@POST
@Path("/{collection_id}/items")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Item addCollectionItem(@PathParam("collection_id") String collectionId, Item item,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Create item in collection(id=" + collectionId + ").");
org.dspace.core.Context context = null;
Item returnItem = null;
try {
context = createContext();
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId,
org.dspace.core.Constants.WRITE);
writeStats(dspaceCollection, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor,
headers, request, context);
log.trace("Creating item in collection(id=" + collectionId + ").");
org.dspace.content.WorkspaceItem workspaceItem = workspaceItemService
.create(context, dspaceCollection, false);
org.dspace.content.Item dspaceItem = workspaceItem.getItem();
log.trace("Adding metadata to item(id=" + dspaceItem.getID() + ").");
if (item.getMetadata() != null) {
for (MetadataEntry entry : item.getMetadata()) {
String data[] = mySplit(entry.getKey());
itemService.addMetadata(context, dspaceItem, data[0], data[1], data[2], entry.getLanguage(),
entry.getValue());
}
}
workspaceItemService.update(context, workspaceItem);
try {
// Must insert the item into workflow
log.trace("Starting workflow for item(id=" + dspaceItem.getID() + ").");
workflowService.start(context, workspaceItem);
} catch (Exception e) {
log.error(
LogHelper.getHeader(context, "Error while starting workflow",
"Item id: " + dspaceItem.getID()),
e);
throw new ContextException("Error while starting workflow for item(id=" + dspaceItem.getID() + ")", e);
}
returnItem = new Item(workspaceItem.getItem(), servletContext, "", context);
context.complete();
} catch (SQLException e) {
processException("Could not add item into collection(id=" + collectionId + "), SQLException. Message: " + e,
context);
} catch (AuthorizeException e) {
processException(
"Could not add item into collection(id=" + collectionId + "), AuthorizeException. Message: " + e,
context);
} catch (ContextException e) {
processException(
"Could not add item into collection(id=" + collectionId + "), ContextException. Message: " + e
.getMessage(),
context);
} finally {
processFinally(context);
}
log.info(
"Item successfully created in collection(id=" + collectionId + "). Item handle=" + returnItem.getHandle());
return returnItem;
}
/**
* Update collection. It replace all properties.
*
* @param collectionId Id of collection in DSpace.
* @param collection Collection which will replace properties of actual collection.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return response 200 if was everything all right. Otherwise 400
* when id of community was incorrect or 401 if was problem with
* permission to write into collection.
* @throws WebApplicationException It is thrown when was problem with database reading or
* writing. Or problem with authorization to collection. Or
* problem with creating context.
*/
@PUT
@Path("/{collection_id}")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response updateCollection(@PathParam("collection_id") String collectionId,
org.dspace.rest.common.Collection collection, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Updating collection(id=" + collectionId + ").");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId,
org.dspace.core.Constants.WRITE);
writeStats(dspaceCollection, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor,
headers, request, context);
collectionService.setMetadataSingleValue(context, dspaceCollection,
MD_NAME, collection.getName(), null);
collectionService.setMetadataSingleValue(context, dspaceCollection,
MD_LICENSE, collection.getLicense(), null);
// dspaceCollection.setLogo(collection.getLogo()); // TODO Add this option.
collectionService.setMetadataSingleValue(context, dspaceCollection,
MD_COPYRIGHT_TEXT, collection.getCopyrightText(), null);
collectionService.setMetadataSingleValue(context, dspaceCollection,
MD_INTRODUCTORY_TEXT, collection.getIntroductoryText(), null);
collectionService.setMetadataSingleValue(context, dspaceCollection,
MD_SHORT_DESCRIPTION, collection.getShortDescription(), null);
collectionService.setMetadataSingleValue(context, dspaceCollection,
MD_SIDEBAR_TEXT, collection.getSidebarText(), null);
collectionService.update(context, dspaceCollection);
context.complete();
} catch (ContextException e) {
processException(
"Could not update collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(),
context);
} catch (SQLException e) {
processException("Could not update collection(id=" + collectionId + "), SQLException. Message: " + e,
context);
} catch (AuthorizeException e) {
processException("Could not update collection(id=" + collectionId + "), AuthorizeException. Message: " + e,
context);
} finally {
processFinally(context);
}
log.info("Collection(id=" + collectionId + ") successfully updated.");
return Response.ok().build();
}
/**
* Delete collection.
*
* @param collectionId Id of collection which will be deleted.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return response code OK(200) if was everything all right.
* Otherwise return NOT_FOUND(404) if was id of community or
* collection incorrect. Or (UNAUTHORIZED)401 if was problem with
* permission to community or collection.
* @throws WebApplicationException Thrown if there was a problem with creating context or problem
* with database reading or writing. Or problem with deleting
* collection caused by IOException or authorization.
*/
@DELETE
@Path("/{collection_id}")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response deleteCollection(@PathParam("collection_id") String collectionId,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Delete collection(id=" + collectionId + ").");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.Collection dspaceCollection = findCollection(context, collectionId,
org.dspace.core.Constants.DELETE);
writeStats(dspaceCollection, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwardedfor,
headers, request, context);
collectionService.delete(context, dspaceCollection);
collectionService.update(context, dspaceCollection);
context.complete();
} catch (ContextException e) {
processException(
"Could not delete collection(id=" + collectionId + "), ContextException. Message: " + e.getMessage(),
context);
} catch (SQLException e) {
processException("Could not delete collection(id=" + collectionId + "), SQLException. Message: " + e,
context);
} catch (AuthorizeException e) {
processException("Could not delete collection(id=" + collectionId + "), AuthorizeException. Message: " + e,
context);
} catch (IOException e) {
processException("Could not delete collection(id=" + collectionId + "), IOException. Message: " + e,
context);
} finally {
processFinally(context);
}
log.info("Collection(id=" + collectionId + ") was successfully deleted.");
return Response.ok().build();
}
/**
* Delete item in collection.
*
* @param collectionId Id of collection which will be deleted.
* @param itemId Id of item in colletion.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return It returns status code: OK(200). NOT_FOUND(404) if item or
* collection was not found, UNAUTHORIZED(401) if user is not
* allowed to delete item or permission to write into collection.
* @throws WebApplicationException It can be thrown by: SQLException, when was problem with
* database reading or writting. AuthorizeException, when was
* problem with authorization to item or collection.
* IOException, when was problem with removing item.
* ContextException, when was problem with creating context of
* DSpace.
*/
@DELETE
@Path("/{collection_id}/items/{item_id}")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response deleteCollectionItem(@PathParam("collection_id") String collectionId,
@PathParam("item_id") String itemId,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Delete item(id=" + itemId + ") in collection(id=" + collectionId + ").");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.Collection dspaceCollection = collectionService
.findByIdOrLegacyId(context, collectionId);
org.dspace.content.Item item = itemService.findByIdOrLegacyId(context, itemId);
if (dspaceCollection == null) {
//throw collection not exist
log.warn("Collection(id=" + itemId + ") was not found!");
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
if (item == null) {
//throw item not exist
log.warn("Item(id=" + itemId + ") was not found!");
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
if (!authorizeService.authorizeActionBoolean(context, item, Constants.REMOVE)
|| !authorizeService.authorizeActionBoolean(context, dspaceCollection, Constants.REMOVE)) {
//throw auth
if (context.getCurrentUser() != null) {
log.error(
"User(" + context.getCurrentUser().getEmail() + ") does not have permission to delete item!");
} else {
log.error("User(anonymous) has not permission to delete item!");
}
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
collectionService.removeItem(context, dspaceCollection, item);
collectionService.update(context, dspaceCollection);
itemService.update(context, item);
writeStats(dspaceCollection, UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor,
headers, request, context);
writeStats(item, UsageEvent.Action.REMOVE, user_ip, user_agent, xforwardedfor, headers, request, context);
context.complete();
} catch (ContextException e) {
processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId
+ "), ContextException. Message: " + e.getMessage(), context);
} catch (SQLException e) {
processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId
+ "), SQLException. Message: " + e, context);
} catch (AuthorizeException e) {
processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId
+ "), AuthorizeException. Message: " + e, context);
} catch (IOException e) {
processException("Could not delete item(id=" + itemId + ") in collection(id=" + collectionId
+ "), IOException. Message: " + e, context);
} finally {
processFinally(context);
}
log.info("Item(id=" + itemId + ") in collection(id=" + collectionId + ") was successfully deleted.");
return Response.ok().build();
}
/**
* Search for first collection with passed name.
*
* @param name Name of collection.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @return It returns null if collection was not found. Otherwise returns
* first founded collection.
* @throws WebApplicationException A general exception a servlet can throw when it encounters difficulty.
*/
@POST
@Path("/find-collection")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Collection findCollectionByName(String name, @Context HttpHeaders headers) throws WebApplicationException {
log.info("Searching for first collection with name=" + name + ".");
org.dspace.core.Context context = null;
Collection collection = null;
try {
context = createContext();
List<org.dspace.content.Collection> dspaceCollections = collectionService.findAll(context);
//TODO, this would be more efficient with a findByName query
for (org.dspace.content.Collection dspaceCollection : dspaceCollections) {
if (authorizeService
.authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ)) {
if (dspaceCollection.getName().equals(name)) {
collection = new Collection(dspaceCollection, servletContext, "", context, 100, 0);
break;
}
}
}
context.complete();
} catch (SQLException e) {
processException(
"Something went wrong while searching for collection(name=" + name + ") from database. Message: "
+ e, context);
} catch (ContextException e) {
processException(
"Something went wrong while searching for collection(name=" + name + "), ContextError. Message: "
+ e.getMessage(), context);
} finally {
processFinally(context);
}
if (collection == null) {
log.info("Collection was not found.");
} else {
log.info("Collection was found with id(" + collection.getUUID() + ").");
}
return collection;
}
/**
* Find collection from DSpace database. It is encapsulation of method
* org.dspace.content.Collection.find with checking if item exist and if
* user logged into context has permission to do passed action.
*
* @param context Context of actual logged user.
* @param id Id of collection in DSpace.
* @param action Constant from org.dspace.core.Constants.
* @return It returns DSpace collection.
* @throws WebApplicationException Is thrown when item with passed id is not exists and if user
* has no permission to do passed action.
*/
private org.dspace.content.Collection findCollection(org.dspace.core.Context context, String id, int action)
throws WebApplicationException {
org.dspace.content.Collection collection = null;
try {
collection = collectionService.findByIdOrLegacyId(context, id);
if (collection == null) {
context.abort();
log.warn("Collection(id=" + id + ") was not found!");
throw new WebApplicationException(Response.Status.NOT_FOUND);
} else if (!authorizeService.authorizeActionBoolean(context, collection, action)) {
context.abort();
if (context.getCurrentUser() != null) {
log.error("User(" + context.getCurrentUser().getEmail() + ") has not permission to "
+ getActionString(action) + " collection!");
} else {
log.error("User(anonymous) has not permission to " + getActionString(action) + " collection!");
}
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
} catch (SQLException e) {
processException("Something get wrong while finding collection(id=" + id + "). SQLException, Message: " + e,
context);
}
return collection;
}
}

View File

@@ -1,19 +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.rest;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.server.ResourceConfig;
public class DSpaceRestApplication extends ResourceConfig {
public DSpaceRestApplication() {
register(JacksonFeature.class);
packages("org.dspace.rest");
}
}

View File

@@ -1,215 +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.rest;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.rest.common.FilteredCollection;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.usage.UsageEvent;
/*
* This class provides the items within a collection evaluated against a set of Item Filters.
*
* @author Terry Brady, Georgetown University
*/
@Path("/filtered-collections")
public class FilteredCollectionsResource extends Resource {
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(FilteredCollectionsResource.class);
/**
* Return array of all collections in DSpace. You can add more properties
* through expand parameter.
*
* @param expand String in which is what you want to add to returned instance
* of collection. Options are: "all", "parentCommunityList",
* "parentCommunity", "topCommunity", "items", "license" and "logo".
* If you want to use multiple options, it must be separated by commas.
* @param limit Limit value for items in list in collection. Default value is
* 100.
* @param offset Offset of start index in list of items of collection. Default
* value is 0.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param filters Comma separated list of Item Filters to use to evaluate against
* the items in a collection
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param servletContext Context of the servlet container.
* @param headers If you want to access the collections as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return array of collection, on which has logged user permission
* to view.
* @throws WebApplicationException It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException).
*/
@GET
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public org.dspace.rest.common.FilteredCollection[] getCollections(@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("100")
Integer limit,
@QueryParam("offset") @DefaultValue("0")
Integer offset,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("filters") @DefaultValue("is_item")
String filters,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context ServletContext servletContext,
@Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading all filtered collections.(offset=" + offset + ",limit=" + limit + ")");
org.dspace.core.Context context = null;
List<FilteredCollection> collections = new ArrayList<FilteredCollection>();
try {
context = createContext();
if (!((limit != null) && (limit >= 0) && (offset != null) && (offset >= 0))) {
log.warn("Paging was badly set.");
limit = 100;
offset = 0;
}
List<org.dspace.content.Collection> dspaceCollections = collectionService.findAll(context, limit, offset);
for (org.dspace.content.Collection dspaceCollection : dspaceCollections) {
if (authorizeService
.authorizeActionBoolean(context, dspaceCollection, org.dspace.core.Constants.READ)) {
FilteredCollection collection = new org.dspace.rest.common.FilteredCollection(dspaceCollection,
servletContext,
filters, expand,
context, limit,
offset);
collections.add(collection);
writeStats(dspaceCollection, UsageEvent.Action.VIEW, user_ip, user_agent,
xforwardedfor, headers, request, context);
}
}
context.complete();
} catch (SQLException e) {
processException("Something went wrong while reading collections from database. Message: " + e, context);
} catch (ContextException e) {
processException("Something went wrong while reading collections, ContextError. Message: " + e.getMessage(),
context);
} finally {
processFinally(context);
}
log.trace("All collections were successfully read.");
return collections.toArray(new org.dspace.rest.common.FilteredCollection[0]);
}
/**
* Return instance of collection with passed id. You can add more properties
* through expand parameter.
*
* @param collection_id Id of collection in DSpace.
* @param expand String in which is what you want to add to returned instance
* of collection. Options are: "all", "parentCommunityList",
* "parentCommunity", "topCommunity", "items", "license" and "logo".
* If you want to use multiple options, it must be separated by commas.
* @param limit Limit value for items in list in collection. Default value is
* 100.
* @param offset Offset of start index in list of items of collection. Default
* value is 0.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param filters Comma separated list of Item Filters to use to evaluate against
* the items in a collection
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @param servletContext Context of the servlet container.
* @return Return instance of collection. It can also return status code
* NOT_FOUND(404) if id of collection is incorrect or status code
* UNATHORIZED(401) if user has no permission to read collection.
* @throws WebApplicationException It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException). It is thrown by NOT_FOUND and
* UNATHORIZED status codes, too.
*/
@GET
@Path("/{collection_id}")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public org.dspace.rest.common.FilteredCollection getCollection(@PathParam("collection_id") String collection_id,
@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("1000") Integer
limit,
@QueryParam("offset") @DefaultValue("0") Integer
offset,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@QueryParam("filters") @DefaultValue("is_item")
String filters,
@Context HttpHeaders headers,
@Context HttpServletRequest request,
@Context ServletContext servletContext) {
org.dspace.core.Context context = null;
FilteredCollection retColl = new org.dspace.rest.common.FilteredCollection();
try {
context = createContext();
org.dspace.content.Collection collection = collectionService.findByIdOrLegacyId(context, collection_id);
if (authorizeService.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) {
writeStats(collection, UsageEvent.Action.VIEW, user_ip,
user_agent, xforwardedfor, headers, request, context);
retColl = new org.dspace.rest.common.FilteredCollection(
collection, servletContext, filters, expand, context, limit, offset);
} else {
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
context.complete();
} catch (SQLException e) {
processException(e.getMessage(), context);
} catch (ContextException e) {
processException(String.format("Could not read collection %s. %s", collection_id, e.getMessage()),
context);
} finally {
processFinally(context);
}
return retColl;
}
}

View File

@@ -1,217 +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.rest;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.content.service.SiteService;
import org.dspace.rest.common.ItemFilter;
import org.dspace.rest.common.ItemFilterQuery;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.rest.filter.ItemFilterSet;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.usage.UsageEvent;
/*
* This class retrieves items by a constructed metadata query evaluated against a set of Item Filters.
*
* @author Terry Brady, Georgetown University
*/
@Path("/filtered-items")
public class FilteredItemsResource extends Resource {
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance()
.getMetadataSchemaService();
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected SiteService siteService = ContentServiceFactory.getInstance().getSiteService();
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(FilteredItemsResource.class);
/**
* Return instance of collection with passed id. You can add more properties
* through expand parameter.
*
* @param expand String in which is what you want to add to returned instance
* of collection. Options are: "all", "parentCommunityList",
* "parentCommunity", "items", "license" and "logo". If you want
* to use multiple options, it must be separated by commas.
* @param limit Limit value for items in list in collection. Default value is
* 100.
* @param offset Offset of start index in list of items of collection. Default
* value is 0.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param filters Comma separated list of Item Filters to use to evaluate against
* the items in a collection
* @param query_field List of metadata fields to evaluate in a metadata query.
* Each list value is used in conjunction with a query_op and query_field.
* @param query_op List of metadata operators to use in a metadata query.
* Each list value is used in conjunction with a query_field and query_field.
* @param query_val List of metadata values to evaluate in a metadata query.
* Each list value is used in conjunction with a query_value and query_op.
* @param collSel List of collections to query.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @param servletContext Context of the servlet container.
* @return Return instance of collection. It can also return status code
* NOT_FOUND(404) if id of collection is incorrect or status code
* UNATHORIZED(401) if user has no permission to read collection.
* @throws WebApplicationException It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException). It is thrown by NOT_FOUND and
* UNATHORIZED status codes, too.
*/
@GET
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public org.dspace.rest.common.ItemFilter getItemQuery(@QueryParam("expand") String expand,
@QueryParam("limit") @DefaultValue("100") Integer limit,
@QueryParam("offset") @DefaultValue("0") Integer offset,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@QueryParam("filters") @DefaultValue("is_item,all_filters")
String filters,
@QueryParam("query_field[]") @DefaultValue("dc.title")
List<String> query_field,
@QueryParam("query_op[]") @DefaultValue("exists")
List<String> query_op,
@QueryParam("query_val[]") @DefaultValue("") List<String>
query_val,
@QueryParam("collSel[]") @DefaultValue("") List<String>
collSel,
@Context HttpHeaders headers,
@Context HttpServletRequest request,
@Context ServletContext servletContext) {
org.dspace.core.Context context = null;
ItemFilterSet itemFilterSet = new ItemFilterSet(filters, true);
ItemFilter result = itemFilterSet.getAllFiltersFilter();
try {
context = createContext();
int index = Math.min(query_field.size(), Math.min(query_op.size(), query_val.size()));
List<ItemFilterQuery> itemFilterQueries = new ArrayList<ItemFilterQuery>();
for (int i = 0; i < index; i++) {
itemFilterQueries.add(new ItemFilterQuery(query_field.get(i), query_op.get(i), query_val.get(i)));
}
String regexClause = configurationService.getProperty("rest.regex-clause");
if (regexClause == null) {
regexClause = "";
}
List<UUID> uuids = getUuidsFromStrings(collSel);
List<List<MetadataField>> listFieldList = getMetadataFieldsList(context, query_field);
Iterator<org.dspace.content.Item> childItems = itemService
.findByMetadataQuery(context, listFieldList, query_op, query_val, uuids, regexClause, offset, limit);
int count = itemFilterSet.processSaveItems(context, servletContext, childItems, true, expand);
writeStats(siteService.findSite(context), UsageEvent.Action.VIEW, user_ip, user_agent, xforwardedfor,
headers, request, context);
result.annotateQuery(query_field, query_op, query_val);
result.setUnfilteredItemCount(count);
context.complete();
} catch (IOException e) {
processException(e.getMessage(), context);
} catch (SQLException e) {
processException(e.getMessage(), context);
} catch (AuthorizeException e) {
processException(e.getMessage(), context);
} catch (ContextException e) {
processException("Unauthorized filtered item query. " + e.getMessage(), context);
} finally {
processFinally(context);
}
return result;
}
private List<List<MetadataField>> getMetadataFieldsList(org.dspace.core.Context context, List<String> query_field)
throws SQLException {
List<List<MetadataField>> listFieldList = new ArrayList<List<MetadataField>>();
for (String s : query_field) {
ArrayList<MetadataField> fields = new ArrayList<MetadataField>();
listFieldList.add(fields);
if (s.equals("*")) {
continue;
}
String schema = "";
String element = "";
String qualifier = null;
String[] parts = s.split("\\.");
if (parts.length > 0) {
schema = parts[0];
}
if (parts.length > 1) {
element = parts[1];
}
if (parts.length > 2) {
qualifier = parts[2];
}
if (Item.ANY.equals(qualifier)) {
for (MetadataField mf : metadataFieldService
.findFieldsByElementNameUnqualified(context, schema, element)) {
fields.add(mf);
}
} else {
MetadataField mf = metadataFieldService.findByElement(context, schema, element, qualifier);
if (mf != null) {
fields.add(mf);
}
}
}
return listFieldList;
}
private List<UUID> getUuidsFromStrings(List<String> collSel) {
List<UUID> uuids = new ArrayList<UUID>();
for (String s : collSel) {
try {
uuids.add(UUID.fromString(s));
} catch (IllegalArgumentException e) {
log.warn("Invalid collection UUID: " + s);
}
}
return uuids;
}
}

View File

@@ -1,60 +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.rest;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.apache.logging.log4j.Logger;
import org.dspace.rest.common.ItemFilter;
/**
* Class which provides read methods over the metadata registry.
*
* @author Terry Brady, Georgetown University
*/
@Path("/filters")
public class FiltersResource {
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(FiltersResource.class);
/**
* Return all Use Case Item Filters in DSpace.
*
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return array of metadata schemas.
* @throws WebApplicationException It can be caused by creating context or while was problem
* with reading community from database(SQLException).
*/
@GET
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public ItemFilter[] getFilters(@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading all Item Filters.");
return ItemFilter.getItemFilters(ItemFilter.ALL, false).toArray(new ItemFilter[0]);
}
}

View File

@@ -1,109 +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.rest;
import java.sql.SQLException;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.DSpaceObjectService;
import org.dspace.core.Constants;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.rest.common.Collection;
import org.dspace.rest.common.Community;
import org.dspace.rest.common.DSpaceObject;
import org.dspace.rest.common.Item;
import org.dspace.rest.exceptions.ContextException;
/**
* Created with IntelliJ IDEA.
* User: peterdietz
* Date: 10/7/13
* Time: 1:54 PM
* To change this template use File | Settings | File Templates.
*/
@Path("/handle")
public class HandleResource extends Resource {
protected HandleService handleService = HandleServiceFactory.getInstance().getHandleService();
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HandleResource.class);
@GET
@Path("/{prefix}/{suffix}")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public org.dspace.rest.common.DSpaceObject getObject(@PathParam("prefix") String prefix,
@PathParam("suffix") String suffix,
@QueryParam("expand") String expand,
@javax.ws.rs.core.Context HttpHeaders headers) {
DSpaceObject dSpaceObject = new DSpaceObject();
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.DSpaceObject dso = handleService.resolveToObject(context, prefix + "/" + suffix);
if (dso == null) {
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
DSpaceObjectService dSpaceObjectService = ContentServiceFactory.getInstance().getDSpaceObjectService(dso);
log.info("DSO Lookup by handle: [" + prefix + "] / [" + suffix + "] got result of: " + dSpaceObjectService
.getTypeText(dso) + "_" + dso.getID());
if (authorizeService.authorizeActionBoolean(context, dso, org.dspace.core.Constants.READ)) {
switch (dso.getType()) {
case Constants.COMMUNITY:
dSpaceObject = new Community((org.dspace.content.Community) dso, servletContext, expand,
context);
break;
case Constants.COLLECTION:
dSpaceObject = new Collection((org.dspace.content.Collection) dso, servletContext, expand,
context, null, null);
break;
case Constants.ITEM:
dSpaceObject = new Item((org.dspace.content.Item) dso, servletContext, expand, context);
break;
default:
dSpaceObject = new DSpaceObject(dso, servletContext);
break;
}
} else {
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
context.complete();
} catch (SQLException e) {
log.error(e.getMessage());
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
} catch (ContextException e) {
processException(
"Could not read handle(prefix=" + prefix + "), (suffix=" + suffix + ") ContextException. Message:" + e
.getMessage(),
context);
} finally {
processFinally(context);
}
return dSpaceObject;
}
}

View File

@@ -1,140 +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.rest;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Site;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.SiteService;
import org.dspace.rest.common.HierarchyCollection;
import org.dspace.rest.common.HierarchyCommunity;
import org.dspace.rest.common.HierarchySite;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
/*
* This class retrieves the community hierarchy in an optimized format.
*
* @author Terry Brady, Georgetown University
*/
@Path("/hierarchy")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public class HierarchyResource extends Resource {
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(HierarchyResource.class);
protected SiteService siteService = ContentServiceFactory.getInstance().getSiteService();
protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
/**
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the collection as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return instance of collection. It can also return status code
* NOT_FOUND(404) if id of collection is incorrect or status code
* @throws UnsupportedEncodingException The Character Encoding is not supported.
* @throws WebApplicationException It is thrown when was problem with database reading
* (SQLException) or problem with creating
* context(ContextException). It is thrown by NOT_FOUND and
* UNATHORIZED status codes, too.
*/
@GET
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public HierarchySite getHierarchy(
@QueryParam("userAgent") String user_agent, @QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws UnsupportedEncodingException, WebApplicationException {
org.dspace.core.Context context = null;
HierarchySite repo = new HierarchySite();
try {
context = createContext();
Site site = siteService.findSite(context);
repo.setId(site.getID().toString());
repo.setName(site.getName());
repo.setHandle(site.getHandle());
List<Community> dspaceCommunities = communityService.findAllTop(context);
processCommunity(context, repo, dspaceCommunities);
} catch (Exception e) {
processException(e.getMessage(), context);
} finally {
if (context != null) {
try {
context.complete();
} catch (SQLException e) {
log.error(e.getMessage() + " occurred while trying to close");
}
}
}
return repo;
}
private void processCommunity(org.dspace.core.Context context, HierarchyCommunity parent,
List<Community> communities) throws SQLException {
if (communities == null) {
return;
}
if (communities.size() == 0) {
return;
}
List<HierarchyCommunity> parentComms = new ArrayList<HierarchyCommunity>();
parent.setCommunities(parentComms);
for (Community comm : communities) {
if (!authorizeService.authorizeActionBoolean(context, comm, org.dspace.core.Constants.READ)) {
continue;
}
HierarchyCommunity mycomm = new HierarchyCommunity(comm.getID().toString(), comm.getName(),
comm.getHandle());
parentComms.add(mycomm);
List<Collection> colls = comm.getCollections();
if (colls.size() > 0) {
List<HierarchyCollection> myColls = new ArrayList<HierarchyCollection>();
mycomm.setCollections(myColls);
for (Collection coll : colls) {
if (!authorizeService.authorizeActionBoolean(context, coll, org.dspace.core.Constants.READ)) {
continue;
}
HierarchyCollection mycoll = new HierarchyCollection(coll.getID().toString(), coll.getName(),
coll.getHandle());
myColls.add(mycoll);
}
}
processCommunity(context, mycomm, comm.getSubcommunities());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,738 +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.rest;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.NonUniqueMetadataException;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.content.service.MetadataSchemaService;
import org.dspace.content.service.SiteService;
import org.dspace.rest.common.MetadataField;
import org.dspace.rest.common.MetadataSchema;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.usage.UsageEvent;
/**
* Class which provides read methods over the metadata registry.
*
* @author Terry Brady, Georgetown University
*
* GET /registries/schema - Return the list of schemas in the registry
* GET /registries/schema/{schema_prefix} - Returns the specified schema
* GET /registries/schema/{schema_prefix}/metadata-fields/{element} - Returns the metadata field within a schema
* with an unqualified element name
* GET /registries/schema/{schema_prefix}/metadata-fields/{element}/{qualifier} - Returns the metadata field
* within a schema with a qualified element name
* POST /registries/schema/ - Add a schema to the schema registry
* POST /registries/schema/{schema_prefix}/metadata-fields - Add a metadata field to the specified schema
* GET /registries/metadata-fields/{field_id} - Return the specified metadata field
* PUT /registries/metadata-fields/{field_id} - Update the specified metadata field
* DELETE /registries/metadata-fields/{field_id} - Delete the specified metadata field from the metadata field registry
* DELETE /registries/schema/{schema_id} - Delete the specified schema from the schema registry
*
* Note: intentionally not providing since there is no date to update other than the namespace
* PUT /registries/schema/{schema_id}
*/
@Path("/registries")
public class MetadataRegistryResource extends Resource {
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
protected MetadataSchemaService metadataSchemaService = ContentServiceFactory.getInstance()
.getMetadataSchemaService();
protected SiteService siteService = ContentServiceFactory.getInstance().getSiteService();
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(MetadataRegistryResource.class);
/**
* Return all metadata registry items in DSpace.
*
* @param expand String in which is what you want to add to returned instance
* of metadata schema. Options are: "all", "fields". Default value "fields".
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the metadata schema as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return array of metadata schemas.
* @throws WebApplicationException It can be caused by creating context or while was problem
* with reading schema from database(SQLException).
*/
@GET
@Path("/schema")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public MetadataSchema[] getSchemas(@QueryParam("expand") @DefaultValue("fields") String expand,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading all metadata schemas.");
org.dspace.core.Context context = null;
ArrayList<MetadataSchema> metadataSchemas = null;
try {
context = createContext();
List<org.dspace.content.MetadataSchema> schemas = metadataSchemaService.findAll(context);
metadataSchemas = new ArrayList<MetadataSchema>();
for (org.dspace.content.MetadataSchema schema : schemas) {
metadataSchemas.add(new MetadataSchema(schema, expand, context));
}
context.complete();
} catch (SQLException e) {
processException("Could not read metadata schemas, SQLException. Message:" + e, context);
} catch (ContextException e) {
processException("Could not read metadata schemas, ContextException. Message:" + e.getMessage(), context);
} finally {
processFinally(context);
}
log.trace("All metadata schemas successfully read.");
return metadataSchemas.toArray(new MetadataSchema[0]);
}
/**
* Returns metadata schema with basic properties. If you want more, use expand
* parameter or method for metadata fields.
*
* @param schemaPrefix Prefix for schema in DSpace.
* @param expand String in which is what you want to add to returned instance
* of metadata schema. Options are: "all", "fields". Default value "fields".
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the metadata schema as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return instance of org.dspace.rest.common.MetadataSchema.
* @throws WebApplicationException Thrown if there was a problem with creating context or problem
* with database reading. Also if id/prefix of schema is incorrect
* or logged user into context has no permission to read.
*/
@GET
@Path("/schema/{schema_prefix}")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public MetadataSchema getSchema(@PathParam("schema_prefix") String schemaPrefix,
@QueryParam("expand") @DefaultValue("fields") String expand,
@QueryParam("userIP") String user_ip, @QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading metadata schemas.");
org.dspace.core.Context context = null;
MetadataSchema metadataSchema = null;
try {
context = createContext();
org.dspace.content.MetadataSchema schema = metadataSchemaService.find(context, schemaPrefix);
metadataSchema = new MetadataSchema(schema, expand, context);
if (schema == null) {
processException(String.format("Schema not found for index %s", schemaPrefix), context);
}
context.complete();
} catch (SQLException e) {
processException("Could not read metadata schema, SQLException. Message:" + e, context);
} catch (ContextException e) {
processException("Could not read metadata schema, ContextException. Message:" + e.getMessage(), context);
} finally {
processFinally(context);
}
log.trace("Metadata schemas successfully read.");
return metadataSchema;
}
/**
* Returns metadata field with basic properties.
*
* @param schemaPrefix Prefix for schema in DSpace.
* @param element Unqualified element name for field in the metadata registry.
* @param expand String in which is what you want to add to returned instance
* of the metadata field. Options are: "all", "parentSchema". Default value "".
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the community as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return instance of org.dspace.rest.common.MetadataField.
* @throws WebApplicationException Thrown if there was a problem with creating context or problem
* with database reading. Also if id of field is incorrect
* or logged user into context has no permission to read.
*/
@GET
@Path("/schema/{schema_prefix}/metadata-fields/{element}")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public MetadataField getMetadataFieldUnqualified(@PathParam("schema_prefix") String schemaPrefix,
@PathParam("element") String element,
@QueryParam("expand") String expand,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
return getMetadataFieldQualified(schemaPrefix, element, "", expand, user_ip, user_agent, xforwardedfor, headers,
request);
}
/**
* Returns metadata field with basic properties.
*
* @param schemaPrefix Prefix for schema in DSpace.
* @param element Element name for field in the metadata registry.
* @param qualifier Element name qualifier for field in the metadata registry.
* @param expand String in which is what you want to add to returned instance
* of the metadata field. Options are: "all", "parentSchema". Default value "".
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the community as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return instance of org.dspace.rest.common.MetadataField.
* @throws WebApplicationException Thrown if there was a problem with creating context or problem
* with database reading. Also if id of field is incorrect
* or logged user into context has no permission to read.
*/
@GET
@Path("/schema/{schema_prefix}/metadata-fields/{element}/{qualifier}")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public MetadataField getMetadataFieldQualified(@PathParam("schema_prefix") String schemaPrefix,
@PathParam("element") String element,
@PathParam("qualifier") @DefaultValue("") String qualifier,
@QueryParam("expand") String expand,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading metadata field.");
org.dspace.core.Context context = null;
MetadataField metadataField = null;
try {
context = createContext();
org.dspace.content.MetadataSchema schema = metadataSchemaService.find(context, schemaPrefix);
if (schema == null) {
log.error(String.format("Schema not found for prefix %s", schemaPrefix));
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
org.dspace.content.MetadataField field = metadataFieldService
.findByElement(context, schema, element, qualifier);
if (field == null) {
log.error(String.format("Field %s.%s.%s not found", schemaPrefix, element, qualifier));
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
metadataField = new MetadataField(schema, field, expand, context);
context.complete();
} catch (SQLException e) {
processException("Could not read metadata field, SQLException. Message:" + e, context);
} catch (ContextException e) {
processException("Could not read metadata field, ContextException. Message:" + e.getMessage(), context);
} finally {
processFinally(context);
}
log.trace("Metadata field successfully read.");
return metadataField;
}
/**
* Returns metadata field with basic properties.
*
* @param fieldId Id of metadata field in DSpace.
* @param expand String in which is what you want to add to returned instance
* of the metadata field. Options are: "all", "parentSchema". Default value "parentSchema".
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the community as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return instance of org.dspace.rest.common.MetadataField.
* @throws WebApplicationException Thrown if there was a problem with creating context or problem
* with database reading. Also if id of field is incorrect
* or logged user into context has no permission to read.
*/
@GET
@Path("/metadata-fields/{field_id}")
@Produces( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public MetadataField getMetadataField(@PathParam("field_id") Integer fieldId,
@QueryParam("expand") @DefaultValue("parentSchema") String expand,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Reading metadata field.");
org.dspace.core.Context context = null;
MetadataField metadataField = null;
try {
context = createContext();
org.dspace.content.MetadataField field = metadataFieldService.find(context, fieldId);
if (field == null) {
log.error(String.format("Metadata Field %d not found", fieldId));
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
org.dspace.content.MetadataSchema schema = field.getMetadataSchema();
if (schema == null) {
log.error(String.format("Parent Schema not found for Metadata Field %d not found", fieldId));
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
metadataField = new MetadataField(schema, field, expand, context);
context.complete();
} catch (SQLException e) {
processException("Could not read metadata field, SQLException. Message:" + e, context);
} catch (ContextException e) {
processException("Could not read metadata field, ContextException. Message:" + e.getMessage(), context);
} finally {
processFinally(context);
}
log.trace("Metadata field successfully read.");
return metadataField;
}
/**
* Create schema in the schema registry. Creating a schema is restricted to admin users.
*
* @param schema Schema that will be added to the metadata registry.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the schema as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return response 200 if was everything all right. Otherwise 400
* when id of community was incorrect or 401 if was problem with
* permission to write into collection.
* Returns the schema (schemaId), if was all ok.
* @throws WebApplicationException It can be thrown by SQLException, AuthorizeException and
* ContextException.
*/
@POST
@Path("/schema")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public MetadataSchema createSchema(MetadataSchema schema, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Creating a schema.");
org.dspace.core.Context context = null;
MetadataSchema retSchema = null;
try {
context = createContext();
if (!authorizeService.isAdmin(context)) {
context.abort();
String user = "anonymous";
if (context.getCurrentUser() != null) {
user = context.getCurrentUser().getEmail();
}
log.error("User(" + user + ") does not have permission to create a metadata schema!");
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
log.debug(String.format("Admin user creating schema with namespace %s and prefix %s", schema.getNamespace(),
schema.getPrefix()));
org.dspace.content.MetadataSchema dspaceSchema = metadataSchemaService
.create(context, schema.getPrefix(), schema.getNamespace());
log.debug("Creating return object.");
retSchema = new MetadataSchema(dspaceSchema, "", context);
writeStats(siteService.findSite(context), UsageEvent.Action.CREATE, user_ip, user_agent, xforwardedfor,
headers, request, context);
context.complete();
log.info("Schema created" + retSchema.getPrefix());
} catch (SQLException e) {
processException("Could not create new metadata schema, SQLException. Message: " + e, context);
} catch (ContextException e) {
processException("Could not create new metadata schema, ContextException. Message: " + e.getMessage(),
context);
} catch (AuthorizeException e) {
processException("Could not create new metadata schema, AuthorizeException. Message: " + e.getMessage(),
context);
} catch (NonUniqueMetadataException e) {
processException(
"Could not create new metadata schema, NonUniqueMetadataException. Message: " + e.getMessage(),
context);
} catch (Exception e) {
processException("Could not create new metadata schema, Exception. Class: " + e.getClass(), context);
} finally {
processFinally(context);
}
return retSchema;
}
/**
* Create a new metadata field within a schema.
* Creating a metadata field is restricted to admin users.
*
* @param schemaPrefix Prefix for schema in DSpace.
* @param field Field that will be added to the metadata registry for a schema.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the schema as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return response 200 if was everything all right. Otherwise 400
* when id of community was incorrect or 401 if was problem with
* permission to write into collection.
* Returns the field (with fieldId), if was all ok.
* @throws WebApplicationException It can be thrown by SQLException, AuthorizeException and
* ContextException.
*/
@POST
@Path("/schema/{schema_prefix}/metadata-fields")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public MetadataField createMetadataField(@PathParam("schema_prefix") String schemaPrefix,
MetadataField field, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info(String.format("Creating metadataField within schema %s.", schemaPrefix));
org.dspace.core.Context context = null;
MetadataField retField = null;
try {
context = createContext();
if (!authorizeService.isAdmin(context)) {
context.abort();
String user = "anonymous";
if (context.getCurrentUser() != null) {
user = context.getCurrentUser().getEmail();
}
log.error("User(" + user + ") does not have permission to create a metadata field!");
throw new WebApplicationException(Response.Status.UNAUTHORIZED);
}
org.dspace.content.MetadataSchema schema = metadataSchemaService.find(context, schemaPrefix);
if (schema == null) {
log.error(String.format("Schema not found for prefix %s", schemaPrefix));
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
org.dspace.content.MetadataField dspaceField = metadataFieldService
.create(context, schema, field.getElement(), field.getQualifier(), field.getDescription());
writeStats(siteService.findSite(context), UsageEvent.Action.CREATE, user_ip, user_agent, xforwardedfor,
headers, request, context);
retField = new MetadataField(schema, dspaceField, "", context);
context.complete();
log.info("Metadata field created within schema" + retField.getName());
} catch (SQLException e) {
processException("Could not create new metadata field, SQLException. Message: " + e, context);
} catch (ContextException e) {
processException("Could not create new metadata field, ContextException. Message: " + e.getMessage(),
context);
} catch (AuthorizeException e) {
processException("Could not create new metadata field, AuthorizeException. Message: " + e.getMessage(),
context);
} catch (NonUniqueMetadataException e) {
processException(
"Could not create new metadata field, NonUniqueMetadataException. Message: " + e.getMessage(), context);
} catch (Exception e) {
processException("Could not create new metadata field, Exception. Message: " + e.getMessage(), context);
} finally {
processFinally(context);
}
return retField;
}
//@PUT
//@Path("/schema/{schema_prefix}")
//Assumption - there are no meaningful fields to update for a schema
/**
* Update metadata field. Replace all information about community except the id and the containing schema.
*
* @param fieldId Id of the field in the DSpace metdata registry.
* @param field Instance of the metadata field which will replace actual metadata field in
* DSpace.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the metadata field as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Response 200 if was all ok. Otherwise 400 if was id incorrect or
* 401 if logged user has no permission to update the metadata field.
* @throws WebApplicationException Thrown if there was a problem with creating context or problem
* with database reading or writing. Or problem with writing to
* community caused by authorization.
*/
@PUT
@Path("/metadata-fields/{field_id}")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response updateMetadataField(@PathParam("field_id") Integer fieldId, MetadataField field,
@QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor, @Context HttpHeaders headers,
@Context HttpServletRequest request)
throws WebApplicationException {
log.info("Updating metadata field(id=" + fieldId + ").");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.MetadataField dspaceField = metadataFieldService.find(context, fieldId);
if (field == null) {
log.error(String.format("Metadata Field %d not found", fieldId));
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
writeStats(siteService.findSite(context), UsageEvent.Action.UPDATE, user_ip, user_agent, xforwardedfor,
headers, request, context);
dspaceField.setElement(field.getElement());
dspaceField.setQualifier(field.getQualifier());
dspaceField.setScopeNote(field.getDescription());
metadataFieldService.update(context, dspaceField);
context.complete();
} catch (SQLException e) {
processException("Could not update metadata field(id=" + fieldId + "), AuthorizeException. Message:" + e,
context);
} catch (ContextException e) {
processException("Could not update metadata field(id=" + fieldId + "), ContextException Message:" + e,
context);
} catch (AuthorizeException e) {
processException("Could not update metadata field(id=" + fieldId + "), AuthorizeException. Message:" + e,
context);
} catch (NonUniqueMetadataException e) {
processException(
"Could not update metadata field(id=" + fieldId + "), NonUniqueMetadataException. Message:" + e,
context);
} catch (IOException e) {
processException("Could not update metadata field(id=" + fieldId + "), IOException. Message:" + e, context);
} finally {
processFinally(context);
}
log.info("Metadata Field(id=" + fieldId + ") has been successfully updated.");
return Response.ok().build();
}
/**
* Delete metadata field from the DSpace metadata registry
*
* @param fieldId Id of the metadata field in DSpace.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the metadata field as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return response code OK(200) if was everything all right.
* Otherwise return NOT_FOUND(404) if was id of metadata field is incorrect.
* Or (UNAUTHORIZED)401 if was problem with permission to metadata field.
* @throws WebApplicationException Thrown if there was a problem with creating context or problem
* with database reading or deleting. Or problem with deleting
* metadata field caused by IOException or authorization.
*/
@DELETE
@Path("/metadata-fields/{field_id}")
public Response deleteMetadataField(@PathParam("field_id") Integer fieldId, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Deleting metadata field(id=" + fieldId + ").");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.MetadataField dspaceField = metadataFieldService.find(context, fieldId);
if (dspaceField == null) {
log.error(String.format("Metadata Field %d not found", fieldId));
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
writeStats(siteService.findSite(context), UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor,
headers,
request, context);
metadataFieldService.delete(context, dspaceField);
context.complete();
} catch (SQLException e) {
processException("Could not delete metadata field(id=" + fieldId + "), SQLException. Message:" + e,
context);
} catch (AuthorizeException e) {
processException("Could not delete metadata field(id=" + fieldId + "), AuthorizeException. Message:" + e,
context);
} catch (ContextException e) {
processException(
"Could not delete metadata field(id=" + fieldId + "), ContextException. Message:" + e.getMessage(),
context);
} finally {
processFinally(context);
}
log.info("Metadata field(id=" + fieldId + ") was successfully deleted.");
return Response.status(Response.Status.OK).build();
}
/**
* Delete metadata schema from the DSpace metadata registry
*
* @param schemaId Id of the metadata schema in DSpace.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the metadata schema as the user logged into the
* context. The value of the "rest-dspace-token" header must be set
* to the token received from the login method response.
* @param request Servlet's HTTP request object.
* @return Return response code OK(200) if was everything all right.
* Otherwise return NOT_FOUND(404) if was id of metadata schema is incorrect.
* Or (UNAUTHORIZED)401 if was problem with permission to metadata schema.
* @throws WebApplicationException Thrown if there was a problem with creating context or problem
* with database reading or deleting. Or problem with deleting
* metadata schema caused by IOException or authorization.
*/
@DELETE
@Path("/schema/{schema_id}")
public Response deleteSchema(@PathParam("schema_id") Integer schemaId, @QueryParam("userIP") String user_ip,
@QueryParam("userAgent") String user_agent,
@QueryParam("xforwardedfor") String xforwardedfor,
@Context HttpHeaders headers, @Context HttpServletRequest request)
throws WebApplicationException {
log.info("Deleting metadata schema(id=" + schemaId + ").");
org.dspace.core.Context context = null;
try {
context = createContext();
org.dspace.content.MetadataSchema dspaceSchema = metadataSchemaService.find(context, schemaId);
if (dspaceSchema == null) {
log.error(String.format("Metadata Schema %d not found", schemaId));
throw new WebApplicationException(Response.Status.NOT_FOUND);
}
writeStats(siteService.findSite(context), UsageEvent.Action.DELETE, user_ip, user_agent, xforwardedfor,
headers,
request, context);
metadataSchemaService.delete(context, dspaceSchema);
context.complete();
} catch (SQLException e) {
processException("Could not delete metadata schema(id=" + schemaId + "), SQLException. Message:" + e,
context);
} catch (AuthorizeException e) {
processException("Could not delete metadata schema(id=" + schemaId + "), AuthorizeException. Message:" + e,
context);
} catch (ContextException e) {
processException(
"Could not delete metadata schema(id=" + schemaId + "), ContextException. Message:" + e.getMessage(),
context);
} finally {
processFinally(context);
}
log.info("Metadata schema(id=" + schemaId + ") was successfully deleted.");
return Response.status(Response.Status.OK).build();
}
}

View File

@@ -1,212 +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.rest;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import org.apache.logging.log4j.Logger;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.usage.UsageEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* Superclass of all resource classes in REST API. It has methods for creating
* context, write statistics, processsing exceptions, splitting a key of
* metadata, string representation of action and method for getting the logged
* in user from the token in request header.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*/
public class Resource {
@javax.ws.rs.core.Context
public ServletContext servletContext;
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(Resource.class);
private static final boolean writeStatistics;
static {
writeStatistics = DSpaceServicesFactory.getInstance().getConfigurationService()
.getBooleanProperty("rest.stats", false);
}
/**
* Create context to work with DSpace database. It can create context
* with or without a logged in user (retrieved from SecurityContextHolder). Throws
* WebApplicationException caused by: SQLException if there was a problem
* with reading from database. Throws AuthorizeException if there was
* a problem with authorization to read from the database. Throws Exception
* if there was a problem creating context.
*
* @return Newly created context with the logged in user unless the specified user was null.
* If user is null, create the context without a logged in user.
* @throws ContextException Thrown in case of a problem creating context. Can be caused by
* SQLException error in creating context or finding the user to
* log in. Can be caused by AuthorizeException if there was a
* problem authorizing the found user.
* @throws SQLException An exception that provides information on a database access error or other errors.
*/
protected static org.dspace.core.Context createContext() throws ContextException, SQLException {
org.dspace.core.Context context = new org.dspace.core.Context();
//context.getDBConnection().setAutoCommit(false); // Disable autocommit.
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null) {
Collection<SimpleGrantedAuthority> specialGroups = (Collection<SimpleGrantedAuthority>) authentication
.getAuthorities();
for (SimpleGrantedAuthority grantedAuthority : specialGroups) {
context.setSpecialGroup(EPersonServiceFactory.getInstance().getGroupService()
.findByName(context, grantedAuthority.getAuthority())
.getID());
}
context.setCurrentUser(
EPersonServiceFactory.getInstance().getEPersonService().findByEmail(context, authentication.getName()));
}
return context;
}
/**
* Records a statistics event about an object used via REST API.
*
* @param dspaceObject DSpace object on which a request was performed.
* @param action Action that was performed.
* @param user_ip User's IP address.
* @param user_agent User agent string (specifies browser used and its version).
* @param xforwardedfor When accessed via a reverse proxy, the application sees the proxy's IP as the
* source of the request. The proxy may be configured to add the
* "X-Forwarded-For" HTTP header containing the original IP of the client
* so that the reverse-proxied application can get the client's IP.
* @param headers If you want to access the item as the user logged into the
* context. The header "rest-dspace-token" with the token passed
* from the login method must be set.
* @param request Servlet's HTTP request object.
* @param context Context which must be aborted.
*/
protected void writeStats(DSpaceObject dspaceObject, UsageEvent.Action action,
String user_ip, String user_agent, String xforwardedfor, HttpHeaders headers,
HttpServletRequest request, Context context) {
if (!writeStatistics) {
return;
}
if ((user_ip == null) || (user_ip.length() == 0)) {
DSpaceServicesFactory.getInstance().getEventService()
.fireEvent(new UsageEvent(action, request, context, dspaceObject));
} else {
DSpaceServicesFactory.getInstance().getEventService().fireEvent(
new UsageEvent(action, user_ip, user_agent, xforwardedfor, context, dspaceObject));
}
log.debug("fired event");
}
/**
* Process exception, print message to logger error stream and abort DSpace
* context.
*
* @param message Message, which will be printed to error stream.
* @param context Context which must be aborted.
* @throws WebApplicationException This exception is throw for user of REST api.
*/
protected static void processException(String message, org.dspace.core.Context context)
throws WebApplicationException {
if ((context != null) && (context.isValid())) {
context.abort();
}
log.error(message);
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
/**
* Process finally statement. It will print message to logger error stream
* and abort DSpace context, if was not properly ended.
*
* @param context Context which must be aborted.
* @throws WebApplicationException This exception is thrown for user of REST API.
*/
protected void processFinally(org.dspace.core.Context context) throws WebApplicationException {
if ((context != null) && (context.isValid())) {
context.abort();
log.error("Something get wrong. Aborting context in finally statement.");
throw new WebApplicationException(Response.Status.INTERNAL_SERVER_ERROR);
}
}
/**
* Split string with regex ".".
*
* @param key String which will be splitted.
* @return String array filed with separated string.
*/
protected String[] mySplit(String key) {
ArrayList<String> list = new ArrayList<String>();
int prev = 0;
for (int i = 0; i < key.length(); i++) {
if (key.charAt(i) == '.') {
list.add(key.substring(prev, i));
prev = i + 1;
} else if (i + 1 == key.length()) {
list.add(key.substring(prev, i + 1));
}
}
if (list.size() == 2) {
list.add(null);
}
return list.toArray(new String[0]);
}
/**
* Return string representation of values
* org.dspace.core.Constants.{READ,WRITE,DELETE}.
*
* @param action Constant from org.dspace.core.Constants.*
* @return String representation. read or write or delete.
*/
protected String getActionString(int action) {
String actionStr;
switch (action) {
case org.dspace.core.Constants.READ:
actionStr = "read";
break;
case org.dspace.core.Constants.WRITE:
actionStr = "write";
break;
case org.dspace.core.Constants.DELETE:
actionStr = "delete";
break;
case org.dspace.core.Constants.REMOVE:
actionStr = "remove";
break;
case org.dspace.core.Constants.ADD:
actionStr = "add";
break;
default:
actionStr = "(?action?)";
break;
}
return actionStr;
}
}

View File

@@ -1,301 +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.rest;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.Iterator;
import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.dspace.authenticate.AuthenticationMethod;
import org.dspace.authenticate.ShibAuthentication;
import org.dspace.authenticate.factory.AuthenticateServiceFactory;
import org.dspace.authenticate.service.AuthenticationService;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.rest.common.Status;
import org.dspace.rest.exceptions.ContextException;
import org.dspace.utils.DSpace;
/**
* Root of RESTful api. It provides login and logout. Also have method for
* printing every method which is provides by RESTful api.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*/
@Path("/")
public class RestIndex {
protected EPersonService epersonService = EPersonServiceFactory.getInstance().getEPersonService();
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(RestIndex.class);
/**
* Return html page with information about REST api. It contains methods all
* methods provide by REST api.
*
* @param servletContext Context of the servlet container.
* @return HTML page which has information about all methods of REST API.
*/
@GET
@Produces(MediaType.TEXT_HTML)
public String sayHtmlHello(@Context ServletContext servletContext) {
// TODO Better graphics, add arguments to all methods. (limit, offset, item and so on)
return "<html><title>DSpace REST - index</title>" +
"<body>"
+ "<h1>DSpace REST API (Deprecated)</h1>" +
"<em>This REST API is deprecated and will be removed in v8." +
" Please use the new Server API webapp instead.</em><br/>" +
"Server path: " + servletContext.getContextPath() +
"<h2>Index</h2>" +
"<ul>" +
"<li>GET / - Return this page.</li>" +
"<li>GET /test - Return the string \"REST api is running\" for testing purposes.</li>" +
"<li>POST /login - Method for logging into the DSpace RESTful API. You must post the parameters \"email\"" +
" and \"password\". Example: \"email=test@dspace&password=pass\". Returns a JSESSIONID cookie which can " +
"be used for future authenticated requests.</li>" +
"<li>POST /logout - Method for logging out of the DSpace RESTful API. The request must include the " +
"\"rest-dspace-token\" token</li> header." +
"</ul>" +
"<h2>Communities</h2>" +
"<ul>" +
"<li>GET /communities - Return an array of all communities in DSpace.</li>" +
"<li>GET /communities/top-communities - Returns an array of all top-leve communities in DSpace.</li>" +
"<li>GET /communities/{communityId} - Returns a community with the specified ID.</li>" +
"<li>GET /communities/{communityId}/collections - Returns an array of collections of the specified " +
"community.</li>" +
"<li>GET /communities/{communityId}/communities - Returns an array of subcommunities of the specified " +
"community.</li>" +
"<li>POST /communities - Create a new top-level community. You must post a community.</li>" +
"<li>POST /communities/{communityId}/collections - Create a new collection in the specified community. " +
"You must post a collection.</li>" +
"<li>POST /communities/{communityId}/communities - Create a new subcommunity in the specified community. " +
"You must post a community.</li>" +
"<li>PUT /communities/{communityId} - Update the specified community.</li>" +
"<li>DELETE /communities/{communityId} - Delete the specified community.</li>" +
"<li>DELETE /communities/{communityId}/collections/{collectionId} - Delete the specified collection in " +
"the specified community.</li>" +
"<li>DELETE /communities/{communityId}/communities/{communityId2} - Delete the specified subcommunity " +
"(communityId2) in the specified community (communityId).</li>" +
"</ul>" +
"<h2>Collections</h2>" +
"<ul>" +
"<li>GET /collections - Return all DSpace collections in array.</li>" +
"<li>GET /collections/{collectionId} - Return a collection with the specified ID.</li>" +
"<li>GET /collections/{collectionId}/items - Return all items of the specified collection.</li>" +
"<li>POST /collections/{collectionId}/items - Create an item in the specified collection. You must post " +
"an item.</li>" +
"<li>POST /collections/find-collection - Find a collection by name.</li>" +
"<li>PUT /collections/{collectionId} </li> - Update the specified collection. You must post a collection." +
"<li>DELETE /collections/{collectionId} - Delete the specified collection from DSpace.</li>" +
"<li>DELETE /collections/{collectionId}/items/{itemId} - Delete the specified item (itemId) in the " +
"specified collection (collectionId). </li>" +
"</ul>" +
"<h2>Items</h2>" +
"<ul>" +
"<li>GET /items - Return a list of items.</li>" +
"<li>GET /items/{item id} - Return the specified item.</li>" +
"<li>GET /items/{item id}/metadata - Return metadata of the specified item.</li>" +
"<li>GET /items/{item id}/bitstreams - Return bitstreams of the specified item.</li>" +
"<li>POST /items/find-by-metadata-field - Find items by the specified metadata value.</li>" +
"<li>POST /items/{item id}/metadata - Add metadata to the specified item.</li>" +
"<li>POST /items/{item id}/bitstreams - Add a bitstream to the specified item.</li>" +
"<li>PUT /items/{item id}/metadata - Update metadata in the specified item.</li>" +
"<li>DELETE /items/{item id} - Delete the specified item.</li>" +
"<li>DELETE /items/{item id}/metadata - Clear metadata of the specified item.</li>" +
"<li>DELETE /items/{item id}/bitstreams/{bitstream id} - Delete the specified bitstream of the specified " +
"item.</li>" +
"</ul>" +
"<h2>Bitstreams</h2>" +
"<ul>" +
"<li>GET /bitstreams - Return all bitstreams in DSpace.</li>" +
"<li>GET /bitstreams/{bitstream id} - Return the specified bitstream.</li>" +
"<li>GET /bitstreams/{bitstream id}/policy - Return policies of the specified bitstream.</li>" +
"<li>GET /bitstreams/{bitstream id}/retrieve - Return the contents of the specified bitstream.</li>" +
"<li>POST /bitstreams/{bitstream id}/policy - Add a policy to the specified bitstream.</li>" +
"<li>PUT /bitstreams/{bitstream id}/data - Update the contents of the specified bitstream.</li>" +
"<li>PUT /bitstreams/{bitstream id} - Update metadata of the specified bitstream.</li>" +
"<li>DELETE /bitstreams/{bitstream id} - Delete the specified bitstream from DSpace.</li>" +
"<li>DELETE /bitstreams/{bitstream id}/policy/{policy_id} - Delete the specified bitstream policy.</li>" +
"</ul>" +
"<h2>Hierarchy</h2>" +
"<ul>" +
"<li>GET /hierarchy - Return hierarchy of communities and collections in tree form. Each object is " +
"minimally populated (name, handle, id) for efficient retrieval.</li>" +
"</ul>" +
"<h2>Metadata and Schema Registry</h2>" +
"<ul>" +
"<li>GET /registries/schema - Return the list of metadata schemas in the registry</li>" +
"<li>GET /registries/schema/{schema_prefix} - Returns the specified metadata schema</li>" +
"<li>GET /registries/schema/{schema_prefix}/metadata-fields/{element} - Returns the metadata field within" +
" a schema with an unqualified element name</li>" +
"<li>GET /registries/schema/{schema_prefix}/metadata-fields/{element}/{qualifier} - Returns the metadata " +
"field within a schema with a qualified element name</li>" +
"<li>POST /registries/schema/ - Add a schema to the schema registry</li>" +
"<li>POST /registries/schema/{schema_prefix}/metadata-fields - Add a metadata field to the specified " +
"schema</li>" +
"<li>GET /registries/metadata-fields/{field_id} - Return the specified metadata field</li>" +
"<li>PUT /registries/metadata-fields/{field_id} - Update the specified metadata field</li>" +
"<li>DELETE /registries/metadata-fields/{field_id} - Delete the specified metadata field from the " +
"metadata field registry</li>" +
"<li>DELETE /registries/schema/{schema_id} - Delete the specified schema from the schema registry</li>" +
"</ul>" +
"<h2>Query/Reporting Tools</h2>" +
"<ul>" +
"<li>GET /reports - Return a list of report tools built on the rest api</li>" +
"<li>GET /reports/{nickname} - Return a redirect to a specific report</li>" +
"<li>GET /filters - Return a list of use case filters available for quality control reporting</li>" +
"<li>GET /filtered-collections - Return collections and item counts based on pre-defined filters</li>" +
"<li>GET /filtered-collections/{collection_id} - Return items and item counts for a collection based on " +
"pre-defined filters</li>" +
"<li>GET /filtered-items - Retrieve a set of items based on a metadata query and a set of filters</li>" +
"</ul>" +
"</body></html> ";
}
/**
* Method only for testing whether the REST API is running.
*
* @return String "REST api is running."
*/
@GET
@Path("/test")
public String test() {
return "REST api is running.";
}
/**
* Method to login a user into REST API.
*
* @return Returns response code OK and a token. Otherwise returns response
* code FORBIDDEN(403).
*/
@POST
@Path("/login")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response login() {
//If you can get here, you are authenticated, the actual login is handled by spring security
return Response.ok().build();
}
@GET
@Path("/shibboleth-login")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response shibbolethLogin() {
//If you can get here, you are authenticated, the actual login is handled by spring security
return Response.ok().build();
}
@GET
@Path("/login-shibboleth")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response shibbolethLoginEndPoint() {
org.dspace.core.Context context = null;
try {
context = Resource.createContext();
AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance()
.getAuthenticationService();
Iterator<AuthenticationMethod> authenticationMethodIterator = authenticationService
.authenticationMethodIterator();
while (authenticationMethodIterator.hasNext()) {
AuthenticationMethod authenticationMethod = authenticationMethodIterator.next();
if (authenticationMethod instanceof ShibAuthentication) {
//TODO: Perhaps look for a better way of handling this ?
org.dspace.services.model.Request currentRequest = new DSpace().getRequestService()
.getCurrentRequest();
String loginPageURL = authenticationMethod
.loginPageURL(context, currentRequest.getHttpServletRequest(),
currentRequest.getHttpServletResponse());
if (StringUtils.isNotBlank(loginPageURL)) {
currentRequest.getHttpServletResponse().sendRedirect(loginPageURL);
}
}
}
context.abort();
} catch (ContextException | SQLException | IOException e) {
Resource.processException("Shibboleth endpoint error: " + e.getMessage(), context);
} finally {
if (context != null && context.isValid()) {
context.abort();
}
}
return Response.ok().build();
}
/**
* Method to logout a user from DSpace REST API. Removes the token and user from
* TokenHolder.
*
* @param headers Request header which contains the header named
* "rest-dspace-token" containing the token as value.
* @return Return response OK, otherwise BAD_REQUEST, if there was a problem with
* logout or the token is incorrect.
*/
@POST
@Path("/logout")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response logout(@Context HttpHeaders headers) {
//If you can get here, you are logged out, this actual logout is handled by spring security
return Response.ok().build();
}
/**
* Method to check current status of the service and logged in user.
*
* okay: true | false
* authenticated: true | false
* epersonEMAIL: user@example.com
* epersonNAME: John Doe
*
* @param headers Request header which contains the header named
* "rest-dspace-token" containing the token as value.
* @return status the Status object with information about REST API
* @throws UnsupportedEncodingException The Character Encoding is not supported.
*/
@GET
@Path("/status")
@Consumes( {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Status status(@Context HttpHeaders headers)
throws UnsupportedEncodingException {
org.dspace.core.Context context = null;
try {
context = Resource.createContext();
EPerson ePerson = context.getCurrentUser();
if (ePerson != null) {
//DB EPerson needed since token won't have full info, need context
EPerson dbEPerson = epersonService.findByEmail(context, ePerson.getEmail());
Status status = new Status(dbEPerson.getEmail(), dbEPerson.getFullName());
return status;
}
} catch (ContextException e) {
Resource.processException("Status context error: " + e.getMessage(), context);
} catch (SQLException e) {
Resource.processException("Status eperson db lookup error: " + e.getMessage(), context);
} finally {
context.abort();
}
//fallback status, unauth
return new Status();
}
}

View File

@@ -1,86 +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.rest;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import org.apache.logging.log4j.Logger;
import org.dspace.rest.common.Report;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Root of RESTful api. It provides login and logout. Also have method for
* printing every method which is provides by RESTful api.
*
* @author Terry Brady, Georgetown University
*/
@Path("/reports")
public class RestReports {
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(RestReports.class);
protected ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService();
public static final String REST_RPT_URL = "rest.report-url.";
/**
* Return html page with information about REST api. It contains methods all
* methods provide by REST api.
*
* @return HTML page which has information about all methods of REST api.
*/
@GET
@Produces(MediaType.APPLICATION_XML)
public Report[] reportIndex()
throws WebApplicationException {
ArrayList<Report> reports = new ArrayList<Report>();
List<String> propNames = configurationService.getPropertyKeys("rest");
for (String propName : propNames) {
if (propName.startsWith(REST_RPT_URL)) {
String nickname = propName.substring(REST_RPT_URL.length());
String url = configurationService.getProperty(propName);
reports.add(new Report(nickname, url));
}
}
return reports.toArray(new Report[0]);
}
@Path("/{report_nickname}")
@GET
public Response customReport(@PathParam("report_nickname") String report_nickname, @Context UriInfo uriInfo)
throws WebApplicationException {
URI uri = null;
if (!report_nickname.isEmpty()) {
log.info(String.format("Seeking report %s", report_nickname));
String url = configurationService.getProperty(REST_RPT_URL + report_nickname);
log.info(String.format("URL for report %s found: [%s]", report_nickname, url));
if (!url.isEmpty()) {
uri = uriInfo.getBaseUriBuilder().path(url).build("");
log.info(String.format("URI for report %s", uri));
}
}
if (uri != null) {
return Response.temporaryRedirect(uri).build();
}
return Response.noContent().build();
}
}

View File

@@ -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.rest.authentication;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dspace.authenticate.AuthenticationMethod;
import org.dspace.authenticate.factory.AuthenticateServiceFactory;
import org.dspace.authenticate.service.AuthenticationService;
import org.dspace.core.Context;
import org.dspace.core.LogHelper;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.dspace.utils.DSpace;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
/**
* The core authentication & authorization provider, this provider is called when logging in & will process
*
* @author Roeland Dillen (roeland at atmire dot com)
* @author kevinvandevelde at atmire.com
*
* FIXME This provider handles both the authorization as well as the authentication,
* due to the way that the DSpace authentication is implemented there is currently no other way to do this.
*/
public class DSpaceAuthenticationProvider implements AuthenticationProvider {
private static final Logger log = LogManager.getLogger();
protected AuthenticationService authenticationService = AuthenticateServiceFactory.getInstance()
.getAuthenticationService();
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Context context = null;
try {
context = new Context();
String name = authentication.getName();
String password = authentication.getCredentials().toString();
HttpServletRequest httpServletRequest = new DSpace().getRequestService().getCurrentRequest()
.getHttpServletRequest();
List<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<>();
int implicitStatus = authenticationService
.authenticateImplicit(context, null, null, null, httpServletRequest);
if (implicitStatus == AuthenticationMethod.SUCCESS) {
log.info(LogHelper.getHeader(context, "login", "type=implicit"));
addSpecialGroupsToGrantedAuthorityList(context, httpServletRequest, grantedAuthorities);
return createAuthenticationToken(password, context, grantedAuthorities);
} else {
int authenticateResult = authenticationService
.authenticate(context, name, password, null, httpServletRequest);
if (AuthenticationMethod.SUCCESS == authenticateResult) {
addSpecialGroupsToGrantedAuthorityList(context, httpServletRequest, grantedAuthorities);
log.info(LogHelper.getHeader(context, "login", "type=explicit"));
return createAuthenticationToken(password, context, grantedAuthorities);
} else {
log.info(LogHelper.getHeader(context, "failed_login",
"email=" + name + ", result=" + authenticateResult));
throw new BadCredentialsException("Login failed");
}
}
} catch (BadCredentialsException e) {
throw e;
} catch (Exception e) {
log.error("Error while authenticating in the rest api", e);
} finally {
if (context != null && context.isValid()) {
try {
context.complete();
} catch (SQLException e) {
log.error(e.getMessage() + " occurred while trying to close", e);
}
}
}
return null;
}
protected void addSpecialGroupsToGrantedAuthorityList(Context context, HttpServletRequest httpServletRequest,
List<SimpleGrantedAuthority> grantedAuthorities)
throws SQLException {
List<Group> groups = authenticationService.getSpecialGroups(context, httpServletRequest);
for (Group group : groups) {
grantedAuthorities.add(new SimpleGrantedAuthority(group.getName()));
}
}
private Authentication createAuthenticationToken(final String password, final Context context,
final List<SimpleGrantedAuthority> grantedAuthorities) {
EPerson ePerson = context.getCurrentUser();
if (ePerson != null && StringUtils.isNotBlank(ePerson.getEmail())) {
return new UsernamePasswordAuthenticationToken(ePerson.getEmail(), password, grantedAuthorities);
} else {
log.info(LogHelper.getHeader(context, "failed_login",
"No eperson with an non-blank e-mail address found"));
throw new BadCredentialsException("Login failed");
}
}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}

View File

@@ -1,41 +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.rest.authentication;
import java.io.IOException;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
/**
* @author kevinvandevelde at atmire.com
*
* Spring redirects to the home page after a successfull login. This success handles ensures that this is NOT the case.
*/
public class NoRedirectAuthenticationLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@PostConstruct
public void afterPropertiesSet() {
setRedirectStrategy(new NoRedirectStrategy());
}
protected class NoRedirectStrategy implements RedirectStrategy {
@Override
public void sendRedirect(HttpServletRequest request,
HttpServletResponse response, String url) throws IOException {
// no redirect
}
}
}

View File

@@ -1,39 +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.rest.authentication;
import java.io.IOException;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;
/**
* @author kevinvandevelde at atmire.com
*
* Spring redirects to the home page after a successfull logout. This success handles ensures that this is NOT the case.
*/
public class NoRedirectAuthenticationLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
@PostConstruct
public void afterPropertiesSet() {
setRedirectStrategy(new NoRedirectStrategy());
}
protected class NoRedirectStrategy implements RedirectStrategy {
@Override
public void sendRedirect(HttpServletRequest request,
HttpServletResponse response, String url) throws IOException {
// no redirect
}
}
}

View File

@@ -1,199 +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.rest.common;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletContext;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Bundle;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.BundleService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.utils.DSpace;
/**
* Created with IntelliJ IDEA.
* User: peterdietz
* Date: 9/21/13
* Time: 12:54 AM
* To change this template use File | Settings | File Templates.
*/
@XmlRootElement(name = "bitstream")
public class Bitstream extends DSpaceObject {
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
Logger log = org.apache.logging.log4j.LogManager.getLogger(Bitstream.class);
private String bundleName;
private String description;
private String format;
private String mimeType;
private Long sizeBytes;
private DSpaceObject parentObject;
private String retrieveLink;
private CheckSum checkSum;
private Integer sequenceId;
private ResourcePolicy[] policies = null;
public Bitstream() {
}
public Bitstream(org.dspace.content.Bitstream bitstream, ServletContext servletContext, String expand,
Context context)
throws SQLException {
super(bitstream, servletContext);
setup(bitstream, servletContext, expand, context);
}
public void setup(org.dspace.content.Bitstream bitstream, ServletContext servletContext, String expand,
Context context)
throws SQLException {
List<String> expandFields = new ArrayList<String>();
if (expand != null) {
expandFields = Arrays.asList(expand.split(","));
}
//A logo bitstream might not have a bundle...
if (bitstream.getBundles() != null && !bitstream.getBundles().isEmpty()) {
if (bitstreamService.getParentObject(context, bitstream).getType() == Constants.ITEM) {
bundleName = bitstream.getBundles().get(0).getName();
}
}
description = bitstream.getDescription();
format = bitstreamService.getFormatDescription(context, bitstream);
sizeBytes = bitstream.getSizeBytes();
String path = new DSpace().getRequestService().getCurrentRequest().getHttpServletRequest().getContextPath();
retrieveLink = path + "/bitstreams/" + bitstream.getID() + "/retrieve";
mimeType = bitstreamService.getFormat(context, bitstream).getMIMEType();
sequenceId = bitstream.getSequenceID();
CheckSum checkSum = new CheckSum();
checkSum.setCheckSumAlgorith(bitstream.getChecksumAlgorithm());
checkSum.setValue(bitstream.getChecksum());
this.setCheckSum(checkSum);
if (expandFields.contains("parent") || expandFields.contains("all")) {
parentObject = new DSpaceObject(bitstreamService.getParentObject(context, bitstream), servletContext);
} else {
this.addExpand("parent");
}
if (expandFields.contains("policies") || expandFields.contains("all")) {
// Find policies without context.
List<ResourcePolicy> tempPolicies = new ArrayList<ResourcePolicy>();
List<Bundle> bundles = bitstream.getBundles();
for (Bundle bundle : bundles) {
List<org.dspace.authorize.ResourcePolicy> bitstreamsPolicies = bundleService
.getBitstreamPolicies(context, bundle);
for (org.dspace.authorize.ResourcePolicy policy : bitstreamsPolicies) {
if (policy.getdSpaceObject().equals(bitstream)) {
tempPolicies.add(new ResourcePolicy(policy));
}
}
}
policies = tempPolicies.toArray(new ResourcePolicy[0]);
} else {
this.addExpand("policies");
}
if (!expandFields.contains("all")) {
this.addExpand("all");
}
}
public Integer getSequenceId() {
return sequenceId;
}
public void setSequenceId(Integer sequenceId) {
this.sequenceId = sequenceId;
}
public String getBundleName() {
return bundleName;
}
public void setBundleName(String bundleName) {
this.bundleName = bundleName;
}
public void setDescription(String description) {
this.description = description;
}
public void setFormat(String format) {
this.format = format;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
public void setSizeBytes(Long sizeBytes) {
this.sizeBytes = sizeBytes;
}
public void setParentObject(DSpaceObject parentObject) {
this.parentObject = parentObject;
}
public void setRetrieveLink(String retrieveLink) {
this.retrieveLink = retrieveLink;
}
public String getDescription() {
return description;
}
public String getFormat() {
return format;
}
public String getMimeType() {
return mimeType;
}
public Long getSizeBytes() {
return sizeBytes;
}
public String getRetrieveLink() {
return retrieveLink;
}
public DSpaceObject getParentObject() {
return parentObject;
}
public CheckSum getCheckSum() {
return checkSum;
}
public void setCheckSum(CheckSum checkSum) {
this.checkSum = checkSum;
}
public ResourcePolicy[] getPolicies() {
return policies;
}
public void setPolicies(ResourcePolicy[] policies) {
this.policies = policies;
}
}

View File

@@ -1,40 +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.rest.common;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
@XmlType
public class CheckSum {
String checkSumAlgorithm;
String value;
public CheckSum() {
}
@XmlAttribute(name = "checkSumAlgorithm")
public String getCheckSumAlgorith() {
return checkSumAlgorithm;
}
public void setCheckSumAlgorith(String checkSumAlgorith) {
this.checkSumAlgorithm = checkSumAlgorith;
}
@XmlValue
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -1,225 +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.rest.common;
import static org.dspace.content.service.DSpaceObjectService.MD_COPYRIGHT_TEXT;
import static org.dspace.content.service.DSpaceObjectService.MD_INTRODUCTORY_TEXT;
import static org.dspace.content.service.DSpaceObjectService.MD_SHORT_DESCRIPTION;
import static org.dspace.content.service.DSpaceObjectService.MD_SIDEBAR_TEXT;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletContext;
import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.logging.log4j.Logger;
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.core.Context;
/**
* Created with IntelliJ IDEA.
* User: peterdietz
* Date: 5/22/13
* Time: 9:41 AM
*/
@XmlRootElement(name = "collection")
public class Collection extends DSpaceObject {
protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
Logger log = org.apache.logging.log4j.LogManager.getLogger(Collection.class);
//Relationships
private Bitstream logo;
private Community parentCommunity;
private List<Community> parentCommunityList = new ArrayList<>();
private List<Item> items = new ArrayList<>();
//Collection-Metadata
private String license;
private String copyrightText;
private String introductoryText;
private String shortDescription;
private String sidebarText;
//Calculated
private Integer numberItems;
public Collection() {
}
public Collection(org.dspace.content.Collection collection, ServletContext servletContext, String expand,
Context context, Integer limit, Integer offset)
throws SQLException, WebApplicationException {
super(collection, servletContext);
setup(collection, servletContext, expand, context, limit, offset);
}
private void setup(org.dspace.content.Collection collection, ServletContext servletContext, String expand,
Context context, Integer limit, Integer offset)
throws SQLException {
List<String> expandFields = new ArrayList<>();
if (expand != null) {
expandFields = Arrays.asList(expand.split(","));
}
this.setCopyrightText(collectionService.getMetadataFirstValue(collection,
MD_COPYRIGHT_TEXT, org.dspace.content.Item.ANY));
this.setIntroductoryText(collectionService.getMetadataFirstValue(collection,
MD_INTRODUCTORY_TEXT, org.dspace.content.Item.ANY));
this.setShortDescription(collectionService.getMetadataFirstValue(collection,
MD_SHORT_DESCRIPTION, org.dspace.content.Item.ANY));
this.setSidebarText(collectionService.getMetadataFirstValue(collection,
MD_SIDEBAR_TEXT, org.dspace.content.Item.ANY));
if (expandFields.contains("parentCommunityList") || expandFields.contains("all")) {
List<org.dspace.content.Community> parentCommunities = communityService.getAllParents(context, collection);
for (org.dspace.content.Community parentCommunity : parentCommunities) {
this.addParentCommunityList(new Community(parentCommunity, servletContext, null, context));
}
} else {
this.addExpand("parentCommunityList");
}
if (expandFields.contains("parentCommunity") | expandFields.contains("all")) {
org.dspace.content.Community parentCommunity =
(org.dspace.content.Community) collectionService
.getParentObject(context, collection);
this.setParentCommunity(new Community(
parentCommunity, servletContext, null, context));
} else {
this.addExpand("parentCommunity");
}
//TODO: Item paging. limit, offset/page
if (expandFields.contains("items") || expandFields.contains("all")) {
Iterator<org.dspace.content.Item> childItems =
itemService.findByCollection(context, collection, limit, offset);
items = new ArrayList<>();
while (childItems.hasNext()) {
org.dspace.content.Item item = childItems.next();
if (itemService.isItemListedForUser(context, item)) {
items.add(new Item(item, servletContext, null, context));
}
}
} else {
this.addExpand("items");
}
if (expandFields.contains("license") || expandFields.contains("all")) {
setLicense(collectionService.getLicense(collection));
} else {
this.addExpand("license");
}
if (expandFields.contains("logo") || expandFields.contains("all")) {
if (collection.getLogo() != null) {
this.logo = new Bitstream(collection.getLogo(), servletContext, null, context);
}
} else {
this.addExpand("logo");
}
if (!expandFields.contains("all")) {
this.addExpand("all");
}
this.setNumberItems(itemService.countItems(context, collection));
}
public Bitstream getLogo() {
return logo;
}
public Integer getNumberItems() {
return numberItems;
}
public void setNumberItems(Integer numberItems) {
this.numberItems = numberItems;
}
public Community getParentCommunity() {
return parentCommunity;
}
public void setParentCommunity(Community parentCommunity) {
this.parentCommunity = parentCommunity;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
public void setParentCommunityList(List<Community> parentCommunityList) {
this.parentCommunityList = parentCommunityList;
}
public List<Community> getParentCommunityList() {
return parentCommunityList;
}
public void addParentCommunityList(Community parentCommunity) {
this.parentCommunityList.add(parentCommunity);
}
public String getLicense() {
return license;
}
public void setLicense(String license) {
this.license = license;
}
public String getCopyrightText() {
return copyrightText;
}
public void setCopyrightText(String copyrightText) {
this.copyrightText = copyrightText;
}
public String getIntroductoryText() {
return introductoryText;
}
public void setIntroductoryText(String introductoryText) {
this.introductoryText = introductoryText;
}
public String getShortDescription() {
return shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
public String getSidebarText() {
return sidebarText;
}
public void setSidebarText(String sidebarText) {
this.sidebarText = sidebarText;
}
}

View File

@@ -1,217 +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.rest.common;
import static org.dspace.content.service.DSpaceObjectService.MD_COPYRIGHT_TEXT;
import static org.dspace.content.service.DSpaceObjectService.MD_INTRODUCTORY_TEXT;
import static org.dspace.content.service.DSpaceObjectService.MD_SHORT_DESCRIPTION;
import static org.dspace.content.service.DSpaceObjectService.MD_SIDEBAR_TEXT;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletContext;
import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
/**
* Created with IntelliJ IDEA.
* User: peterdietz
* Date: 5/22/13
* Time: 9:41 AM
* To change this template use File | Settings | File Templates.
*/
@XmlRootElement(name = "community")
public class Community extends DSpaceObject {
protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(Community.class);
//Exandable relationships
private Bitstream logo;
private Community parentCommunity;
private String copyrightText;
private String introductoryText;
private String shortDescription;
private String sidebarText;
private Integer countItems;
private List<Community> subcommunities = new ArrayList<>();
private List<Collection> collections = new ArrayList<>();
public Community() {
}
public Community(org.dspace.content.Community community, ServletContext servletContext, String expand,
Context context)
throws SQLException, WebApplicationException {
super(community, servletContext);
setup(community, servletContext, expand, context);
}
private void setup(org.dspace.content.Community community, ServletContext servletContext, String expand,
Context context)
throws SQLException {
List<String> expandFields = new ArrayList<>();
if (expand != null) {
expandFields = Arrays.asList(expand.split(","));
}
this.setCopyrightText(communityService.getMetadataFirstValue(community,
MD_COPYRIGHT_TEXT, org.dspace.content.Item.ANY));
this.setIntroductoryText(communityService.getMetadataFirstValue(community,
MD_INTRODUCTORY_TEXT, org.dspace.content.Item.ANY));
this.setShortDescription(communityService.getMetadataFirstValue(community,
MD_SHORT_DESCRIPTION, org.dspace.content.Item.ANY));
this.setSidebarText(communityService.getMetadataFirstValue(community,
MD_SIDEBAR_TEXT, org.dspace.content.Item.ANY));
this.setCountItems(itemService.countItems(context, community));
if (expandFields.contains("parentCommunity") || expandFields.contains("all")) {
org.dspace.content.Community parentCommunity = (org.dspace.content.Community) communityService
.getParentObject(context, community);
if (parentCommunity != null) {
setParentCommunity(new Community(parentCommunity, servletContext, null, context));
}
} else {
this.addExpand("parentCommunity");
}
if (expandFields.contains("collections") || expandFields.contains("all")) {
List<org.dspace.content.Collection> collections = community.getCollections();
List<org.dspace.rest.common.Collection> restCollections = new ArrayList<>();
for (org.dspace.content.Collection collection : collections) {
if (authorizeService.authorizeActionBoolean(context, collection, org.dspace.core.Constants.READ)) {
restCollections.add(new Collection(collection, servletContext, null, context, null, null));
} else {
log.info("Omitted restricted collection: " + collection.getID() + " _ " + collection.getName());
}
}
setCollections(restCollections);
} else {
this.addExpand("collections");
}
if (expandFields.contains("subCommunities") || expandFields.contains("all")) {
List<org.dspace.content.Community> communities = community.getSubcommunities();
subcommunities = new ArrayList<>();
for (org.dspace.content.Community subCommunity : communities) {
if (authorizeService.authorizeActionBoolean(context, subCommunity, org.dspace.core.Constants.READ)) {
subcommunities.add(new Community(subCommunity, servletContext, null, context));
} else {
log.info(
"Omitted restricted subCommunity: " + subCommunity.getID() + " _ " + subCommunity.getName());
}
}
} else {
this.addExpand("subCommunities");
}
if (expandFields.contains("logo") || expandFields.contains("all")) {
if (community.getLogo() != null) {
logo = new Bitstream(community.getLogo(), servletContext, null, context);
}
} else {
this.addExpand("logo");
}
if (!expandFields.contains("all")) {
this.addExpand("all");
}
}
public List<Collection> getCollections() {
return collections;
}
public void setCollections(List<Collection> collections) {
this.collections = collections;
}
public Integer getCountItems() {
return countItems;
}
public void setCountItems(Integer countItems) {
this.countItems = countItems;
}
public String getSidebarText() {
return sidebarText;
}
public void setSidebarText(String sidebarText) {
this.sidebarText = sidebarText;
}
public String getShortDescription() {
return shortDescription;
}
public void setShortDescription(String shortDescription) {
this.shortDescription = shortDescription;
}
public String getIntroductoryText() {
return introductoryText;
}
public void setIntroductoryText(String introductoryText) {
this.introductoryText = introductoryText;
}
public String getCopyrightText() {
return copyrightText;
}
public void setCopyrightText(String copyrightText) {
this.copyrightText = copyrightText;
}
public Community getParentCommunity() {
return parentCommunity;
}
public void setParentCommunity(Community parentCommunity) {
this.parentCommunity = parentCommunity;
}
public Bitstream getLogo() {
return logo;
}
public void setLogo(Bitstream logo) {
this.logo = logo;
}
// Renamed because of xml annotation exception with this attribute and getSubCommunities.
@XmlElement(name = "subcommunities", required = true)
public List<Community> getSubcommunities() {
return subcommunities;
}
public void setSubcommunities(List<Community> subcommunities) {
this.subcommunities = subcommunities;
}
}

View File

@@ -1,107 +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.rest.common;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletContext;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.atteo.evo.inflector.English;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.DSpaceObjectService;
/**
* Created with IntelliJ IDEA.
* User: peterdietz
* Date: 10/7/13
* Time: 12:11 PM
* To change this template use File | Settings | File Templates.
*/
@XmlRootElement(name = "dspaceobject")
public class DSpaceObject {
private String uuid;
private String name;
private String handle;
private String type;
@XmlElement(name = "link", required = true)
private String link;
@XmlElement(required = true)
private ArrayList<String> expand = new ArrayList<String>();
public DSpaceObject() {
}
public DSpaceObject(org.dspace.content.DSpaceObject dso, ServletContext servletContext) {
setUUID(dso.getID().toString());
setName(dso.getName());
setHandle(dso.getHandle());
DSpaceObjectService dspaceObjectService = ContentServiceFactory.getInstance().getDSpaceObjectService(dso);
setType(dspaceObjectService.getTypeText(dso).toLowerCase());
link = createLink(servletContext);
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getHandle() {
return handle;
}
public void setHandle(String handle) {
this.handle = handle;
}
public String getLink() {
return link;
}
public String getType() {
return this.type;
}
public void setType(String type) {
this.type = type;
}
public List<String> getExpand() {
return expand;
}
public void setExpand(ArrayList<String> expand) {
this.expand = expand;
}
public void addExpand(String expandableAttribute) {
this.expand.add(expandableAttribute);
}
public String getUUID() {
return uuid;
}
public void setUUID(String uuid) {
this.uuid = uuid;
}
private String createLink(ServletContext context) {
return context.getContextPath() + "/" + English.plural(getType()) + "/" + getUUID();
}
}

View File

@@ -1,191 +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.rest.common;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletContext;
import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.logging.log4j.Logger;
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.core.Context;
import org.dspace.rest.filter.ItemFilterSet;
/**
* Retrieve items within a collection that match a specific set of Item Filters of interest
*
* @author Terry Brady, Georgetown University
*/
@XmlRootElement(name = "filtered-collection")
public class FilteredCollection extends DSpaceObject {
protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
Logger log = org.apache.logging.log4j.LogManager.getLogger(FilteredCollection.class);
//Relationships
private Community parentCommunity;
private Community topCommunity;
private List<Community> parentCommunityList = new ArrayList<Community>();
private List<Item> items = new ArrayList<Item>();
private List<ItemFilter> itemFilters = new ArrayList<ItemFilter>();
//Calculated
private Integer numberItems;
private Integer numberItemsProcessed;
public FilteredCollection() {
}
/**
* Evaluate a collection against of set of Item Filters
*
* @param collection DSpace Collection to evaluate
* @param servletContext Context of the servlet container.
* @param filters String representing a list of filters
* @param expand String in which is what you want to add to returned instance
* of collection. Options are: "all", "parentCommunityList",
* "parentCommunity", "items", "license" and "logo". If you want
* to use multiple options, it must be separated by commas.
* @param context The relevant DSpace Context.
* @param limit Limit value for items in list in collection. Default value is 100.
* @param offset Offset of start index in list of items of collection. Default
* value is 0.
* @throws SQLException An exception that provides information on a database access error or other
* errors.
* @throws WebApplicationException Runtime exception for applications.
*/
public FilteredCollection(org.dspace.content.Collection collection, ServletContext servletContext, String filters,
String expand, Context context, Integer limit, Integer offset)
throws SQLException, WebApplicationException {
super(collection, servletContext);
setup(collection, servletContext, expand, context, limit, offset, filters);
}
private void setup(org.dspace.content.Collection collection, ServletContext servletContext, String expand,
Context context, Integer limit, Integer offset, String filters) throws SQLException {
List<String> expandFields = new ArrayList<String>();
if (expand != null) {
expandFields = Arrays.asList(expand.split(","));
}
if (expandFields.contains("parentCommunityList") || expandFields.contains("all")) {
List<org.dspace.content.Community> parentCommunities = communityService.getAllParents(context, collection);
List<Community> parentCommunityList = new ArrayList<Community>();
for (org.dspace.content.Community parentCommunity : parentCommunities) {
parentCommunityList.add(new Community(parentCommunity, servletContext, null, context));
}
this.setParentCommunityList(parentCommunityList);
} else {
this.addExpand("parentCommunityList");
}
if (expandFields.contains("parentCommunity") | expandFields.contains("all")) {
org.dspace.content.Community parentCommunity = collection.getCommunities().get(0);
this.setParentCommunity(new Community(parentCommunity, servletContext, null, context));
} else {
this.addExpand("parentCommunity");
}
if (expandFields.contains("topCommunity") | expandFields.contains("all")) {
List<org.dspace.content.Community> parentCommunities = communityService.getAllParents(context, collection);
if (parentCommunities.size() > 0) {
org.dspace.content.Community topCommunity = parentCommunities.get(parentCommunities.size() - 1);
this.setTopCommunity(new Community(topCommunity, servletContext, null, context));
}
} else {
this.addExpand("topCommunity");
}
boolean reportItems = expandFields.contains("items") || expandFields.contains("all");
ItemFilterSet itemFilterSet = new ItemFilterSet(filters, reportItems);
this.setItemFilters(itemFilterSet.getItemFilters());
this.setNumberItemsProcessed(0);
if (itemFilters.size() > 0) {
Iterator<org.dspace.content.Item> childItems = itemService
.findAllByCollection(context, collection, limit, offset);
int numProc = itemFilterSet
.processSaveItems(context, servletContext, childItems, items, reportItems, expand);
this.setNumberItemsProcessed(numProc);
}
if (!expandFields.contains("all")) {
this.addExpand("all");
}
this.setNumberItems(itemService.countAllItems(context, collection));
}
public Integer getNumberItems() {
return numberItems;
}
public void setNumberItems(Integer numberItems) {
this.numberItems = numberItems;
}
public Integer getNumberItemsProcessed() {
return numberItemsProcessed;
}
public void setNumberItemsProcessed(Integer numberItemsProcessed) {
this.numberItemsProcessed = numberItemsProcessed;
}
public Community getParentCommunity() {
return parentCommunity;
}
public void setParentCommunity(Community parentCommunity) {
this.parentCommunity = parentCommunity;
}
public Community getTopCommunity() {
return topCommunity;
}
public void setTopCommunity(Community topCommunity) {
this.topCommunity = topCommunity;
}
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
public void setParentCommunityList(List<Community> parentCommunityList) {
this.parentCommunityList = parentCommunityList;
}
public List<Community> getParentCommunityList() {
return parentCommunityList;
}
public List<ItemFilter> getItemFilters() {
return itemFilters;
}
public void setItemFilters(List<ItemFilter> itemFilters) {
this.itemFilters = itemFilters;
}
}

View File

@@ -1,24 +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.rest.common;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Used to handle/determine status of REST API.
* Mainly to know your authentication status
*/
@XmlRootElement(name = "collection")
public class HierarchyCollection extends HierarchyObject {
public HierarchyCollection() {
}
public HierarchyCollection(String id, String name, String handle) {
super(id, name, handle);
}
}

View File

@@ -1,44 +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.rest.common;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "community")
public class HierarchyCommunity extends HierarchyObject {
private List<HierarchyCommunity> communities = new ArrayList<HierarchyCommunity>();
private List<HierarchyCollection> collections = new ArrayList<HierarchyCollection>();
public HierarchyCommunity() {
}
public HierarchyCommunity(String id, String name, String handle) {
super(id, name, handle);
}
@XmlElement(name = "community")
public List<HierarchyCommunity> getCommunities() {
return communities;
}
public void setCommunities(List<HierarchyCommunity> communities) {
this.communities = communities;
}
@XmlElement(name = "collection")
public List<HierarchyCollection> getCollections() {
return collections;
}
public void setCollections(List<HierarchyCollection> collections) {
this.collections = collections;
}
}

View File

@@ -1,51 +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.rest.common;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "object")
public class HierarchyObject {
//id may be a numeric id or a uuid depending on the version of DSpace
private String id;
private String name;
private String handle;
public HierarchyObject() {
}
public HierarchyObject(String id, String name, String handle) {
setId(id);
setName(name);
setHandle(handle);
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHandle() {
return handle;
}
public void setHandle(String handle) {
this.handle = handle;
}
}

View File

@@ -1,24 +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.rest.common;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Used to handle/determine status of REST API.
* Mainly to know your authentication status
*/
@XmlRootElement(name = "site")
public class HierarchySite extends HierarchyCommunity {
public HierarchySite() {
}
public HierarchySite(String id, String name, String handle) {
super(id, name, handle);
}
}

View File

@@ -1,219 +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.rest.common;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.ServletContext;
import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.logging.log4j.Logger;
import org.dspace.app.util.factory.UtilServiceFactory;
import org.dspace.app.util.service.MetadataExposureService;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bundle;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
/**
* Created with IntelliJ IDEA.
* User: peterdietz
* Date: 9/19/13
* Time: 4:50 PM
* To change this template use File | Settings | File Templates.
*/
@SuppressWarnings("deprecation")
@XmlRootElement(name = "item")
public class Item extends DSpaceObject {
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected MetadataExposureService metadataExposureService = UtilServiceFactory.getInstance()
.getMetadataExposureService();
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
Logger log = org.apache.logging.log4j.LogManager.getLogger(Item.class);
String isArchived;
String isWithdrawn;
String lastModified;
Collection parentCollection;
List<Collection> parentCollectionList;
List<Community> parentCommunityList;
List<MetadataEntry> metadata;
List<Bitstream> bitstreams;
public Item() {
}
public Item(org.dspace.content.Item item, ServletContext servletContext, String expand, Context context)
throws SQLException, WebApplicationException {
super(item, servletContext);
setup(item, servletContext, expand, context);
}
private void setup(org.dspace.content.Item item, ServletContext servletContext, String expand, Context context)
throws SQLException {
List<String> expandFields = new ArrayList<String>();
if (expand != null) {
expandFields = Arrays.asList(expand.split(","));
}
if (expandFields.contains("metadata") || expandFields.contains("all")) {
metadata = new ArrayList<MetadataEntry>();
List<MetadataValue> metadataValues = itemService.getMetadata(
item, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY,
org.dspace.content.Item.ANY, org.dspace.content.Item.ANY);
for (MetadataValue metadataValue : metadataValues) {
MetadataField metadataField = metadataValue.getMetadataField();
if (!metadataExposureService.isHidden(context,
metadataField.getMetadataSchema().getName(),
metadataField.getElement(),
metadataField.getQualifier())) {
metadata.add(new MetadataEntry(metadataField.toString('.'),
metadataValue.getValue(), metadataValue.getLanguage()));
}
}
} else {
this.addExpand("metadata");
}
this.setArchived(Boolean.toString(item.isArchived()));
this.setWithdrawn(Boolean.toString(item.isWithdrawn()));
this.setLastModified(item.getLastModified().toString());
if (expandFields.contains("parentCollection") || expandFields.contains("all")) {
if (item.getOwningCollection() != null) {
this.parentCollection = new Collection(item.getOwningCollection(),
servletContext, null, context, null, null);
} else {
this.addExpand("parentCollection");
}
} else {
this.addExpand("parentCollection");
}
if (expandFields.contains("parentCollectionList") || expandFields.contains("all")) {
this.parentCollectionList = new ArrayList<Collection>();
List<org.dspace.content.Collection> collections = item.getCollections();
for (org.dspace.content.Collection collection : collections) {
this.parentCollectionList.add(new Collection(collection,
servletContext, null, context, null, null));
}
} else {
this.addExpand("parentCollectionList");
}
if (expandFields.contains("parentCommunityList") || expandFields.contains("all")) {
this.parentCommunityList = new ArrayList<Community>();
List<org.dspace.content.Community> communities = itemService.getCommunities(context, item);
for (org.dspace.content.Community community : communities) {
this.parentCommunityList.add(new Community(community, servletContext, null, context));
}
} else {
this.addExpand("parentCommunityList");
}
//TODO: paging - offset, limit
if (expandFields.contains("bitstreams") || expandFields.contains("all")) {
bitstreams = new ArrayList<Bitstream>();
List<Bundle> bundles = item.getBundles();
for (Bundle bundle : bundles) {
List<org.dspace.content.Bitstream> itemBitstreams = bundle.getBitstreams();
for (org.dspace.content.Bitstream itemBitstream : itemBitstreams) {
if (authorizeService
.authorizeActionBoolean(context, itemBitstream, org.dspace.core.Constants.READ)) {
bitstreams.add(new Bitstream(itemBitstream, servletContext, null, context));
}
}
}
} else {
this.addExpand("bitstreams");
}
if (!expandFields.contains("all")) {
this.addExpand("all");
}
}
public String getArchived() {
return isArchived;
}
public void setArchived(String archived) {
isArchived = archived;
}
public String getWithdrawn() {
return isWithdrawn;
}
public void setWithdrawn(String withdrawn) {
isWithdrawn = withdrawn;
}
public String getLastModified() {
return lastModified;
}
public void setLastModified(String lastModified) {
this.lastModified = lastModified;
}
public Collection getParentCollection() {
return parentCollection;
}
public List<Collection> getParentCollectionList() {
return parentCollectionList;
}
public List<MetadataEntry> getMetadata() {
return metadata;
}
public List<Bitstream> getBitstreams() {
return bitstreams;
}
public List<Community> getParentCommunityList() {
return parentCommunityList;
}
public void setParentCollection(Collection parentCollection) {
this.parentCollection = parentCollection;
}
public void setParentCollectionList(List<Collection> parentCollectionList) {
this.parentCollectionList = parentCollectionList;
}
public void setParentCommunityList(List<Community> parentCommunityList) {
this.parentCommunityList = parentCommunityList;
}
@XmlElement(required = true)
public void setMetadata(List<MetadataEntry> metadata) {
this.metadata = metadata;
}
public void setBitstreams(List<Bitstream> bitstreams) {
this.bitstreams = bitstreams;
}
}

View File

@@ -1,274 +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.rest.common;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.logging.log4j.Logger;
import org.dspace.core.Context;
import org.dspace.core.factory.CoreServiceFactory;
import org.dspace.rest.filter.ItemFilterDefs;
import org.dspace.rest.filter.ItemFilterList;
import org.dspace.rest.filter.ItemFilterTest;
/**
* Use Case Item Filters that match a specific set of criteria.
*
* @author Terry Brady, Georgetown University
*/
@XmlRootElement(name = "item-filter")
public class ItemFilter {
static Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemFilter.class);
private ItemFilterTest itemFilterTest = null;
private String filterName = "";
private String title;
private String description;
private String category;
private String queryAnnotation;
private List<org.dspace.rest.common.Item> items = new ArrayList<org.dspace.rest.common.Item>();
private List<ItemFilterQuery> itemFilterQueries = new ArrayList<ItemFilterQuery>();
private List<MetadataEntry> metadata = new ArrayList<MetadataEntry>();
private Integer itemCount;
private Integer unfilteredItemCount;
private boolean saveItems = false;
public ItemFilter() {
}
public static final String ALL_FILTERS = "all_filters";
public static final String ALL = "all";
public static List<ItemFilter> getItemFilters(String filters, boolean saveItems) {
LinkedHashMap<String, ItemFilterTest> availableTests = new LinkedHashMap<String, ItemFilterTest>();
for (ItemFilterList plugobj :
(ItemFilterList[]) CoreServiceFactory.getInstance()
.getPluginService().getPluginSequence(ItemFilterList.class)) {
for (ItemFilterTest defFilter : plugobj.getFilters()) {
availableTests.put(defFilter.getName(), defFilter);
}
}
List<ItemFilter> itemFilters = new ArrayList<ItemFilter>();
ItemFilter allFilters = new ItemFilter(ItemFilter.ALL_FILTERS, "Matches all specified filters",
"This filter includes all items that matched ALL specified filters",
ItemFilterDefs.CAT_ITEM, saveItems);
if (filters.equals(ALL)) {
for (ItemFilterTest itemFilterDef : availableTests.values()) {
itemFilters.add(new ItemFilter(itemFilterDef, saveItems));
}
itemFilters.add(allFilters);
} else {
for (String filter : Arrays.asList(filters.split(","))) {
if (filter.equals(ItemFilter.ALL_FILTERS)) {
continue;
}
ItemFilterTest itemFilterDef;
itemFilterDef = availableTests.get(filter);
if (itemFilterDef == null) {
continue;
}
itemFilters.add(new ItemFilter(itemFilterDef, saveItems));
}
itemFilters.add(allFilters);
}
return itemFilters;
}
public static ItemFilter getAllFiltersFilter(List<ItemFilter> itemFilters) {
for (ItemFilter itemFilter : itemFilters) {
if (itemFilter.getFilterName().equals(ALL_FILTERS)) {
itemFilter.initCount();
return itemFilter;
}
}
return null;
}
public ItemFilter(ItemFilterTest itemFilterTest, boolean saveItems)
throws WebApplicationException {
this.itemFilterTest = itemFilterTest;
this.saveItems = saveItems;
setup(itemFilterTest.getName(), itemFilterTest.getTitle(),
itemFilterTest.getDescription(), itemFilterTest.getCategory());
}
public ItemFilter(String name, String title, String description, String category, boolean saveItems)
throws WebApplicationException {
this.saveItems = saveItems;
setup(name, title, description, category);
}
private void setup(String name, String title, String description, String category) {
this.setFilterName(name);
this.setTitle(title);
this.setDescription(description);
this.setCategory(category);
}
private void initCount() {
if (itemCount == null) {
itemCount = 0;
}
if (unfilteredItemCount == null) {
unfilteredItemCount = 0;
}
}
public boolean hasItemTest() {
return itemFilterTest != null;
}
public void addItem(org.dspace.rest.common.Item restItem) {
initCount();
if (saveItems) {
items.add(restItem);
}
itemCount++;
}
public boolean testItem(Context context, org.dspace.content.Item item, org.dspace.rest.common.Item restItem) {
initCount();
if (itemFilterTest == null) {
return false;
}
if (itemFilterTest.testItem(context, item)) {
addItem(restItem);
return true;
}
return false;
}
@XmlAttribute(name = "filter-name")
public String getFilterName() {
return filterName;
}
public void setFilterName(String name) {
this.filterName = name;
}
@XmlAttribute(name = "title")
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
@XmlAttribute(name = "category")
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
@XmlAttribute(name = "description")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@XmlAttribute(name = "query-annotation")
public String getQueryAnnotation() {
return queryAnnotation;
}
public void annotateQuery(List<String> query_field, List<String> query_op, List<String> query_val)
throws SQLException {
int index = Math.min(query_field.size(), Math.min(query_op.size(), query_val.size()));
StringBuilder sb = new StringBuilder();
for (int i = 0; i < index; i++) {
if (!sb.toString().isEmpty()) {
sb.append(" and ");
}
sb.append("(");
sb.append(query_field.get(i));
sb.append(" ");
sb.append(query_op.get(i));
sb.append(" ");
sb.append(query_val.get(i));
sb.append(")");
}
setQueryAnnotation(sb.toString());
}
public void setQueryAnnotation(String queryAnnotation) {
this.queryAnnotation = queryAnnotation;
}
@XmlAttribute(name = "item-count")
public Integer getItemCount() {
return itemCount;
}
public void setItemCount(Integer itemCount) {
this.itemCount = itemCount;
}
@XmlAttribute(name = "unfiltered-item-count")
public Integer getUnfilteredItemCount() {
return unfilteredItemCount;
}
public void setUnfilteredItemCount(Integer unfilteredItemCount) {
this.unfilteredItemCount = unfilteredItemCount;
}
public List<org.dspace.rest.common.Item> getItems() {
return items;
}
public void setItems(List<org.dspace.rest.common.Item> items) {
this.items = items;
}
public List<ItemFilterQuery> getItemFilterQueries() {
return itemFilterQueries;
}
public void setItemFilterQueries(List<ItemFilterQuery> itemFilterQueries) {
this.itemFilterQueries = itemFilterQueries;
}
public void initMetadataList(List<String> show_fields) {
if (show_fields != null) {
List<MetadataEntry> returnFields = new ArrayList<MetadataEntry>();
for (String field : show_fields) {
returnFields.add(new MetadataEntry(field, null, null));
}
setMetadata(returnFields);
}
}
public List<MetadataEntry> getMetadata() {
return metadata;
}
@XmlElement(required = true)
public void setMetadata(List<MetadataEntry> metadata) {
this.metadata = metadata;
}
}

View File

@@ -1,77 +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.rest.common;
import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.logging.log4j.Logger;
/**
* Metadata Query for DSpace Items using the REST API
*
* @author Terry Brady, Georgetown University
*/
@XmlRootElement(name = "item-filter-query")
public class ItemFilterQuery {
Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemFilterQuery.class);
private String field = "";
private String operation = "";
private String value = "";
public ItemFilterQuery() {
}
/**
* Construct a metadata query for DSpace items
*
* @param field Name of the metadata field to query
* @param operation Operation to perform on a metadata field
* @param value Query value.
* @throws WebApplicationException Runtime exception for applications.
*/
public ItemFilterQuery(String field, String operation, String value) throws WebApplicationException {
setup(field, operation, value);
}
private void setup(String field, String operation, String value) {
this.setField(field);
this.setOperation(operation);
this.setValue(value);
}
@XmlAttribute(name = "field")
public String getField() {
return field;
}
public void setField(String field) {
this.field = field;
}
@XmlAttribute(name = "operation")
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
@XmlAttribute(name = "value")
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}

View File

@@ -1,77 +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.rest.common;
import java.util.regex.Pattern;
import javax.xml.bind.annotation.XmlRootElement;
/**
* @author peterdietz, Rostislav Novak (Computing and Information Centre, CTU in
* Prague)
*/
@XmlRootElement(name = "metadataentry")
public class MetadataEntry {
String key;
String value;
String language;
public MetadataEntry() {
}
public MetadataEntry(String key, String value, String language) {
this.key = key;
this.value = value;
this.language = language;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String getSchema() {
String[] fieldPieces = key.split(Pattern.quote("."));
return fieldPieces[0];
}
public String getElement() {
String[] fieldPieces = key.split(Pattern.quote("."));
return fieldPieces[1];
}
public String getQualifier() {
String[] fieldPieces = key.split(Pattern.quote("."));
if (fieldPieces.length == 3) {
return fieldPieces[2];
} else {
return null;
}
}
}

View File

@@ -1,132 +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.rest.common;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.dspace.core.Context;
/**
* Metadata field representation
*
* @author Terry Brady, Georgetown University.
*/
@XmlRootElement(name = "field")
public class MetadataField {
private int fieldId;
private String name;
private String element;
private String qualifier;
private String description;
private MetadataSchema parentSchema;
@XmlElement(required = true)
private ArrayList<String> expand = new ArrayList<String>();
public MetadataField() {
}
public MetadataField(org.dspace.content.MetadataSchema schema, org.dspace.content.MetadataField field,
String expand, Context context) throws SQLException, WebApplicationException {
setup(schema, field, expand, context);
}
private void setup(org.dspace.content.MetadataSchema schema, org.dspace.content.MetadataField field, String expand,
Context context) throws SQLException {
List<String> expandFields = new ArrayList<String>();
if (expand != null) {
expandFields = Arrays.asList(expand.split(","));
}
StringBuilder sb = new StringBuilder();
sb.append(schema.getName());
sb.append(".");
sb.append(field.getElement());
if (field.getQualifier() != null) {
sb.append(".");
sb.append(field.getQualifier());
}
this.setName(sb.toString());
this.setFieldId(field.getID());
this.setElement(field.getElement());
this.setQualifier(field.getQualifier());
this.setDescription(field.getScopeNote());
if (expandFields.contains("parentSchema") || expandFields.contains("all")) {
this.addExpand("parentSchema");
parentSchema = new MetadataSchema(schema, "", context);
}
}
public void setParentSchema(MetadataSchema schema) {
this.parentSchema = schema;
}
public MetadataSchema getParentSchema() {
return this.parentSchema;
}
public void setFieldId(int fieldId) {
this.fieldId = fieldId;
}
public void setName(String name) {
this.name = name;
}
public void setElement(String element) {
this.element = element;
}
public void setQualifier(String qualifier) {
this.qualifier = qualifier;
}
public void setDescription(String description) {
this.description = description;
}
public int getFieldId() {
return fieldId;
}
public String getName() {
return name;
}
public String getQualifier() {
return qualifier;
}
public String getElement() {
return element;
}
public String getDescription() {
return description;
}
public List<String> getExpand() {
return expand;
}
public void setExpand(ArrayList<String> expand) {
this.expand = expand;
}
public void addExpand(String expandableAttribute) {
this.expand.add(expandableAttribute);
}
}

View File

@@ -1,105 +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.rest.common;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.ws.rs.WebApplicationException;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.MetadataFieldService;
import org.dspace.core.Context;
/**
* Metadata schema representation
*
* @author Terry Brady, Georgetown University.
*/
@XmlRootElement(name = "schema")
public class MetadataSchema {
protected MetadataFieldService metadataFieldService = ContentServiceFactory.getInstance().getMetadataFieldService();
private int schemaID;
private String prefix;
private String namespace;
@XmlElement(required = true)
private ArrayList<String> expand = new ArrayList<String>();
@XmlElement(name = "fields", required = true)
private List<MetadataField> fields = new ArrayList<MetadataField>();
public MetadataSchema() {
}
public MetadataSchema(org.dspace.content.MetadataSchema schema, String expand, Context context)
throws SQLException, WebApplicationException {
setup(schema, expand, context);
}
private void setup(org.dspace.content.MetadataSchema schema, String expand, Context context) throws SQLException {
List<String> expandFields = new ArrayList<String>();
if (expand != null) {
expandFields = Arrays.asList(expand.split(","));
}
this.setSchemaID(schema.getID());
this.setPrefix(schema.getName());
this.setNamespace(schema.getNamespace());
if (expandFields.contains("fields") || expandFields.contains("all")) {
List<org.dspace.content.MetadataField> fields = metadataFieldService.findAllInSchema(context, schema);
this.addExpand("fields");
for (org.dspace.content.MetadataField field : fields) {
this.fields.add(new MetadataField(schema, field, "", context));
}
}
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public void setNamespace(String namespace) {
this.namespace = namespace;
}
public String getPrefix() {
return prefix;
}
public String getNamespace() {
return namespace;
}
public int getSchemaID() {
return this.schemaID;
}
public void setSchemaID(int schemaID) {
this.schemaID = schemaID;
}
public List<MetadataField> getMetadataFields() {
return fields;
}
public List<String> getExpand() {
return expand;
}
public void setExpand(ArrayList<String> expand) {
this.expand = expand;
}
public void addExpand(String expandableAttribute) {
this.expand.add(expandableAttribute);
}
}

View File

@@ -1,47 +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.rest.common;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Used to handle/determine status of REST API.
* Mainly to know your authentication status
*/
@XmlRootElement(name = "report")
public class Report {
private String nickname;
private String url;
public Report() {
setNickname("na");
setUrl("");
}
public Report(String nickname, String url) {
setNickname(nickname);
setUrl(url);
}
public String getUrl() {
return this.url;
}
public String getNickname() {
return this.nickname;
}
public void setUrl(String url) {
this.url = url;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
}

View File

@@ -1,195 +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.rest.common;
import java.util.Date;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonIgnore;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
@XmlRootElement(name = "resourcepolicy")
public class ResourcePolicy {
public enum Action {
READ, WRITE, DELETE;
}
private Integer id;
private Action action;
private String epersonId; //UUID
private String groupId; //UUID
private String resourceId; //UUID
private String resourceType;
private String rpDescription;
private String rpName;
private String rpType;
private Date startDate;
private Date endDate;
public ResourcePolicy() {
}
public ResourcePolicy(org.dspace.authorize.ResourcePolicy dspacePolicy) {
this.id = dspacePolicy.getID();
switch (dspacePolicy.getAction()) {
case org.dspace.core.Constants.READ:
this.action = Action.READ;
break;
case org.dspace.core.Constants.WRITE:
this.action = Action.WRITE;
break;
case org.dspace.core.Constants.DELETE:
this.action = Action.DELETE;
break;
default:
break;
}
EPerson ePerson = dspacePolicy.getEPerson();
if (ePerson != null) {
this.epersonId = ePerson.getID().toString();
}
Group group = dspacePolicy.getGroup();
if (group != null) {
this.groupId = group.getID().toString();
}
this.resourceId = dspacePolicy.getdSpaceObject().getID().toString();
this.rpDescription = dspacePolicy.getRpDescription();
this.rpName = dspacePolicy.getRpName();
this.rpType = dspacePolicy.getRpType();
this.startDate = dspacePolicy.getStartDate();
this.endDate = dspacePolicy.getEndDate();
switch (dspacePolicy.getdSpaceObject().getType()) {
case org.dspace.core.Constants.BITSTREAM:
this.resourceType = "bitstream";
break;
case org.dspace.core.Constants.ITEM:
this.resourceType = "item";
break;
case org.dspace.core.Constants.COLLECTION:
this.resourceType = "collection";
break;
case org.dspace.core.Constants.COMMUNITY:
this.resourceType = "community";
break;
case org.dspace.core.Constants.BUNDLE:
this.resourceType = "bundle";
break;
default:
this.resourceType = "";
break;
}
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Action getAction() {
return action;
}
@JsonIgnore
public int getActionInt() {
switch (action) {
case READ:
return org.dspace.core.Constants.READ;
case WRITE:
return org.dspace.core.Constants.WRITE;
case DELETE:
return org.dspace.core.Constants.DELETE;
default:
return org.dspace.core.Constants.READ;
}
}
public void setAction(Action action) {
this.action = action;
}
public String getEpersonId() {
return epersonId;
}
public void setEpersonId(String epersonId) {
this.epersonId = epersonId;
}
public String getGroupId() {
return groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
public String getResourceId() {
return resourceId;
}
public void setResourceId(String resourceId) {
this.resourceId = resourceId;
}
public String getResourceType() {
return resourceType;
}
public void setResourceType(String resourceType) {
this.resourceType = resourceType;
}
public String getRpDescription() {
return rpDescription;
}
public void setRpDescription(String rpDescription) {
this.rpDescription = rpDescription;
}
public String getRpName() {
return rpName;
}
public void setRpName(String rpName) {
this.rpName = rpName;
}
public String getRpType() {
return rpType;
}
public void setRpType(String rpType) {
this.rpType = rpType;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
}

View File

@@ -1,111 +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.rest.common;
import javax.xml.bind.annotation.XmlRootElement;
import com.fasterxml.jackson.annotation.JsonProperty;
import org.dspace.app.util.Util;
import org.dspace.eperson.EPerson;
/**
* Determine status of REST API - is it running, accessible and without errors?.
* Find out API version (DSpace major version) and DSpace source version.
* Find out your authentication status.
*/
@XmlRootElement(name = "status")
public class Status {
private boolean okay;
private boolean authenticated;
private String email;
private String fullname;
private String sourceVersion;
private String apiVersion;
public Status() {
setOkay(true);
setSourceVersion(Util.getSourceVersion());
String[] version = Util.getSourceVersion().split("\\.");
setApiVersion(version[0]); // major version
setAuthenticated(false);
}
public Status(String email, String fullname) {
setOkay(true);
setAuthenticated(true);
setEmail(email);
setFullname(fullname);
}
public Status(EPerson eperson) {
setOkay(true);
if (eperson != null) {
setAuthenticated(true);
setEmail(eperson.getEmail());
setFullname(eperson.getFullName());
} else {
setAuthenticated(false);
}
}
@JsonProperty("okay")
public boolean isOkay() {
return this.okay;
}
public void setOkay(boolean okay) {
this.okay = okay;
}
@JsonProperty("authenticated")
public boolean isAuthenticated() {
return authenticated;
}
public void setAuthenticated(boolean authenticated) {
this.authenticated = authenticated;
}
@JsonProperty("email")
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@JsonProperty("fullname")
public String getFullname() {
return fullname;
}
public void setFullname(String fullname) {
this.fullname = fullname;
}
@JsonProperty("sourceVersion")
public String getSourceVersion() {
return this.sourceVersion;
}
public void setSourceVersion(String sourceVersion) {
this.sourceVersion = sourceVersion;
}
@JsonProperty("apiVersion")
public String getApiVersion() {
return this.apiVersion;
}
public void setApiVersion(String apiVersion) {
this.apiVersion = apiVersion;
}
}

View File

@@ -1,31 +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.rest.exceptions;
/**
* Simple exception which only encapsulate classic exception. This exception is
* only for exceptions caused by creating context.
*
* @author Rostislav Novak (Computing and Information Centre, CTU in Prague)
*/
public class ContextException extends Exception {
private static final long serialVersionUID = 1L;
Exception causedBy;
public ContextException(String message, Exception causedBy) {
super(message);
this.causedBy = causedBy;
}
public Exception getCausedBy() {
return causedBy;
}
}

View File

@@ -1,159 +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.rest.filter;
import org.dspace.content.Item;
import org.dspace.core.Context;
/**
* Define the set of use cases for filtering items of interest through the REST API.
*
* @author Terry Brady, Georgetown University
*/
public class ItemFilterDefs implements ItemFilterList {
public static final String CAT_ITEM = "Item Property Filters";
public static final String CAT_BASIC = "Basic Bitstream Filters";
public static final String CAT_MIME = "Bitstream Filters by MIME Type";
public static final String[] MIMES_PDF = {"application/pdf"};
public static final String[] MIMES_JPG = {"image/jpeg"};
private enum EnumItemFilterDefs implements ItemFilterTest {
is_item("Is Item - always true", null, CAT_ITEM) {
public boolean testItem(Context context, Item item) {
return true;
}
},
is_withdrawn("Withdrawn Items", null, CAT_ITEM) {
public boolean testItem(Context context, Item item) {
return item.isWithdrawn();
}
},
is_not_withdrawn("Available Items - Not Withdrawn", null, CAT_ITEM) {
public boolean testItem(Context context, Item item) {
return !item.isWithdrawn();
}
},
is_discoverable("Discoverable Items - Not Private", null, CAT_ITEM) {
public boolean testItem(Context context, Item item) {
return item.isDiscoverable();
}
},
is_not_discoverable("Not Discoverable - Private Item", null, CAT_ITEM) {
public boolean testItem(Context context, Item item) {
return !item.isDiscoverable();
}
},
has_multiple_originals("Item has Multiple Original Bitstreams", null, CAT_BASIC) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.countOriginalBitstream(item) > 1;
}
},
has_no_originals("Item has No Original Bitstreams", null, CAT_BASIC) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.countOriginalBitstream(item) == 0;
}
},
has_one_original("Item has One Original Bitstream", null, CAT_BASIC) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.countOriginalBitstream(item) == 1;
}
},
has_doc_original("Item has a Doc Original Bitstream (PDF, Office, Text, HTML, XML, etc)", null, CAT_MIME) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes()) > 0;
}
},
has_image_original("Item has an Image Original Bitstream", null, CAT_MIME) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.countOriginalBitstreamMimeStartsWith(context, item, "image") > 0;
}
},
has_unsupp_type("Has Other Bitstream Types (not Doc or Image)", null, ItemFilterDefs.CAT_MIME) {
public boolean testItem(Context context, Item item) {
int bitCount = ItemFilterUtil.countOriginalBitstream(item);
if (bitCount == 0) {
return false;
}
int docCount = ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes());
int imgCount = ItemFilterUtil.countOriginalBitstreamMimeStartsWith(context, item, "image");
return (bitCount - docCount - imgCount) > 0;
}
},
has_mixed_original("Item has multiple types of Original Bitstreams (Doc, Image, Other)", null, CAT_MIME) {
public boolean testItem(Context context, Item item) {
int countBit = ItemFilterUtil.countOriginalBitstream(item);
if (countBit <= 1) {
return false;
}
int countDoc = ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes());
if (countDoc > 0) {
return countDoc != countBit;
}
int countImg = ItemFilterUtil.countOriginalBitstreamMimeStartsWith(context, item, "image");
if (countImg > 0) {
return countImg != countBit;
}
return false;
}
},
has_pdf_original("Item has a PDF Original Bitstream", null, CAT_MIME) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.countOriginalBitstreamMime(context, item, MIMES_PDF) > 0;
}
},
has_jpg_original("Item has JPG Original Bitstream", null, CAT_MIME) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.countOriginalBitstreamMime(context, item, MIMES_JPG) > 0;
}
},;
private String title = null;
private String description = null;
private EnumItemFilterDefs(String title, String description, String category) {
this.title = title;
this.description = description;
this.category = category;
}
private EnumItemFilterDefs() {
this(null, null, null);
}
public String getName() {
return name();
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
private String category = null;
public String getCategory() {
return category;
}
}
public ItemFilterDefs() {
}
public ItemFilterTest[] getFilters() {
return EnumItemFilterDefs.values();
}
}

View File

@@ -1,177 +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.rest.filter;
import java.util.regex.Pattern;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.ItemService;
import org.dspace.core.Context;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Define the set of use cases for filtering items of interest through the REST API.
*
* @author Terry Brady, Georgetown University
*/
public class ItemFilterDefsMeta implements ItemFilterList {
protected static ItemService itemService = ContentServiceFactory.getInstance().getItemService();
static Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemFilterDefsMeta.class);
public static final String CAT_META_GEN = "General Metadata Filters";
public static final String CAT_META_SPEC = "Specific Metadata Filters";
public static final String CAT_MOD = "Recently Modified";
private enum EnumItemFilterDefs implements ItemFilterTest {
has_no_title("Has no dc.title", null, CAT_META_SPEC) {
public boolean testItem(Context context, Item item) {
return itemService.getMetadataByMetadataString(item, "dc.title").size() == 0;
}
},
has_no_uri("Has no dc.identifier.uri", null, CAT_META_SPEC) {
public boolean testItem(Context context, Item item) {
return itemService.getMetadataByMetadataString(item, "dc.identifier.uri").size() == 0;
}
},
has_mult_uri("Has multiple dc.identifier.uri", null, CAT_META_SPEC) {
public boolean testItem(Context context, Item item) {
return itemService.getMetadataByMetadataString(item, "dc.identifier.uri").size() > 1;
}
},
has_compound_subject("Has compound subject", null, CAT_META_SPEC) {
public boolean testItem(Context context, Item item) {
String regex = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("rest.report-regex-compound-subject");
return ItemFilterUtil.hasMetadataMatch(item, "dc.subject.*", Pattern.compile(regex));
}
},
has_compound_author("Has compound author", null, CAT_META_SPEC) {
public boolean testItem(Context context, Item item) {
String regex = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("rest.report-regex-compound-author");
return ItemFilterUtil
.hasMetadataMatch(item, "dc.creator,dc.contributor.author", Pattern.compile(regex));
}
},
has_empty_metadata("Has empty metadata", null, CAT_META_GEN) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.hasMetadataMatch(item, "*", Pattern.compile("^\\s*$"));
}
},
has_unbreaking_metadata("Has unbreaking metadata", null, CAT_META_GEN) {
public boolean testItem(Context context, Item item) {
String regex = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("rest.report-regex-unbreaking");
return ItemFilterUtil.hasMetadataMatch(item, "*", Pattern.compile(regex));
}
},
has_long_metadata("Has long metadata field", null, CAT_META_GEN) {
public boolean testItem(Context context, Item item) {
String regex = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("rest.report-regex-long");
return ItemFilterUtil.hasMetadataMatch(item, "*", Pattern.compile(regex));
}
},
has_xml_entity("Has XML entity in metadata", null, CAT_META_GEN) {
public boolean testItem(Context context, Item item) {
String regex = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("rest.report-regex-xml-entity");
return ItemFilterUtil.hasMetadataMatch(item, "*", Pattern.compile(regex));
}
},
has_non_ascii("Has non-ascii in metadata", null, CAT_META_GEN) {
public boolean testItem(Context context, Item item) {
String regex = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("rest.report-regex-non-ascii");
return ItemFilterUtil.hasMetadataMatch(item, "*", Pattern.compile(regex));
}
},
has_desc_url("Has url in description", null, CAT_META_SPEC) {
public boolean testItem(Context context, Item item) {
String regex = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("rest.report-regex-url");
return ItemFilterUtil.hasMetadataMatch(item, "dc.description.*", Pattern.compile(regex));
}
},
has_fulltext_provenance("Has fulltext in provenance", null, CAT_META_SPEC) {
public boolean testItem(Context context, Item item) {
String regex = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("rest.report-regex-fulltext");
return ItemFilterUtil.hasMetadataMatch(item, "dc.description.provenance", Pattern.compile(regex));
}
},
no_fulltext_provenance("Doesn't have fulltext in provenance", null, CAT_META_SPEC) {
public boolean testItem(Context context, Item item) {
String regex = DSpaceServicesFactory.getInstance().getConfigurationService()
.getProperty("rest.report-regex-fulltext");
return !ItemFilterUtil.hasMetadataMatch(item, "dc.description.provenance", Pattern.compile(regex));
}
},
mod_last_day("Modified in last 1 day", null, CAT_MOD) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.recentlyModified(item, 1);
}
},
mod_last_7_days("Modified in last 7 days", null, CAT_MOD) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.recentlyModified(item, 7);
}
},
mod_last_30_days("Modified in last 30 days", null, CAT_MOD) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.recentlyModified(item, 30);
}
},
mod_last_90_days("Modified in last 60 days", null, CAT_MOD) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.recentlyModified(item, 60);
}
},;
private String title = null;
private String description = null;
private EnumItemFilterDefs(String title, String description, String category) {
this.title = title;
this.description = description;
this.category = category;
}
private EnumItemFilterDefs() {
this(null, null, null);
}
public String getName() {
return name();
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
private String category = null;
public String getCategory() {
return category;
}
}
public ItemFilterDefsMeta() {
}
public ItemFilterTest[] getFilters() {
return EnumItemFilterDefs.values();
}
}

View File

@@ -1,206 +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.rest.filter;
import java.util.List;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.rest.filter.ItemFilterUtil.BundleName;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* Define the set of use cases for filtering items of interest through the REST API.
*
* @author Terry Brady, Georgetown University
*/
public class ItemFilterDefsMisc implements ItemFilterList {
public static final String CAT_MISC = "Bitstream Bundle Filters";
public static final String CAT_MIME_SUPP = "Supported MIME Type Filters";
private enum EnumItemFilterDefs implements ItemFilterTest {
has_only_supp_image_type("Item Image Bitstreams are Supported", null, CAT_MIME_SUPP) {
public boolean testItem(Context context, Item item) {
int imageCount = ItemFilterUtil.countOriginalBitstreamMimeStartsWith(context, item, "image/");
if (imageCount == 0) {
return false;
}
int suppImageCount = ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedImageMimeTypes());
return (imageCount == suppImageCount);
}
},
has_unsupp_image_type("Item has Image Bitstream that is Unsupported", null, CAT_MIME_SUPP) {
public boolean testItem(Context context, Item item) {
int imageCount = ItemFilterUtil.countOriginalBitstreamMimeStartsWith(context, item, "image/");
if (imageCount == 0) {
return false;
}
int suppImageCount = ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedImageMimeTypes());
return (imageCount - suppImageCount) > 0;
}
},
has_only_supp_doc_type("Item Document Bitstreams are Supported", null, CAT_MIME_SUPP) {
public boolean testItem(Context context, Item item) {
int docCount = ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes());
if (docCount == 0) {
return false;
}
int suppDocCount = ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedDocumentMimeTypes());
return docCount == suppDocCount;
}
},
has_unsupp_doc_type("Item has Document Bitstream that is Unsupported", null, CAT_MIME_SUPP) {
public boolean testItem(Context context, Item item) {
int docCount = ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes());
if (docCount == 0) {
return false;
}
int suppDocCount = ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getSupportedDocumentMimeTypes());
return (docCount - suppDocCount) > 0;
}
},
has_small_pdf("Has unusually small PDF", null, ItemFilterDefs.CAT_MIME) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil
.countBitstreamSmallerThanMinSize(context, BundleName.ORIGINAL, item, ItemFilterDefs.MIMES_PDF,
"rest.report-pdf-min-size") > 0;
}
},
has_large_pdf("Has unusually large PDF", null, ItemFilterDefs.CAT_MIME) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil
.countBitstreamLargerThanMaxSize(context, BundleName.ORIGINAL, item, ItemFilterDefs.MIMES_PDF,
"rest.report-pdf-max-size") > 0;
}
},
has_unsupported_bundle("Has bitstream in an unsuppored bundle", null, CAT_MISC) {
public boolean testItem(Context context, Item item) {
String[] bundleList = DSpaceServicesFactory.getInstance().getConfigurationService()
.getArrayProperty("rest.report-supp-bundles");
return ItemFilterUtil.hasUnsupportedBundle(item, bundleList);
}
},
has_small_thumbnail("Has unusually small thumbnail", null, CAT_MISC) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil
.countBitstreamSmallerThanMinSize(context, BundleName.THUMBNAIL, item, ItemFilterDefs.MIMES_JPG,
"rest.report-thumbnail-min-size") > 0;
}
},
has_doc_without_text("Has document bitstream without TEXT item", null, ItemFilterDefs.CAT_MIME) {
public boolean testItem(Context context, Item item) {
int countDoc = ItemFilterUtil
.countOriginalBitstreamMime(context, item, ItemFilterUtil.getDocumentMimeTypes());
if (countDoc == 0) {
return false;
}
int countText = ItemFilterUtil.countBitstream(BundleName.TEXT, item);
return countDoc > countText;
}
},
has_original_without_thumbnail("Has original bitstream without thumbnail", null, CAT_MISC) {
public boolean testItem(Context context, Item item) {
int countBit = ItemFilterUtil.countOriginalBitstream(item);
if (countBit == 0) {
return false;
}
int countThumb = ItemFilterUtil.countBitstream(BundleName.THUMBNAIL, item);
return countBit > countThumb;
}
},
has_invalid_thumbnail_name("Has invalid thumbnail name (assumes one thumbnail for each original)", null,
CAT_MISC) {
public boolean testItem(Context context, Item item) {
List<String> originalNames = ItemFilterUtil.getBitstreamNames(BundleName.ORIGINAL, item);
List<String> thumbNames = ItemFilterUtil.getBitstreamNames(BundleName.THUMBNAIL, item);
if (thumbNames.size() != originalNames.size()) {
return false;
}
for (String name : originalNames) {
if (!thumbNames.contains(name + ".jpg")) {
return true;
}
}
return false;
}
},
has_non_generated_thumb("Has non generated thumbnail", null, CAT_MISC) {
public boolean testItem(Context context, Item item) {
String[] generatedThumbDesc = DSpaceServicesFactory.getInstance().getConfigurationService()
.getArrayProperty("rest.report-gen-thumbnail-desc");
int countThumb = ItemFilterUtil.countBitstream(BundleName.THUMBNAIL, item);
if (countThumb == 0) {
return false;
}
int countGen = ItemFilterUtil.countBitstreamByDesc(BundleName.THUMBNAIL, item, generatedThumbDesc);
return (countThumb > countGen);
}
},
no_license("Doesn't have a license", null, CAT_MISC) {
public boolean testItem(Context context, Item item) {
return ItemFilterUtil.countBitstream(BundleName.LICENSE, item) == 0;
}
},
has_license_documentation("Has documentation in the license bundle", null, CAT_MISC) {
public boolean testItem(Context context, Item item) {
List<String> names = ItemFilterUtil.getBitstreamNames(BundleName.LICENSE, item);
for (String name : names) {
if (!name.equals("license.txt")) {
return true;
}
}
return false;
}
},;
private String title = null;
private String description = null;
private EnumItemFilterDefs(String title, String description, String category) {
this.title = title;
this.description = description;
this.category = category;
}
private EnumItemFilterDefs() {
this(null, null, null);
}
public String getName() {
return name();
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
private String category = null;
public String getCategory() {
return category;
}
}
public ItemFilterDefsMisc() {
}
public ItemFilterTest[] getFilters() {
return EnumItemFilterDefs.values();
}
}

View File

@@ -1,138 +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.rest.filter;
import java.sql.SQLException;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Item;
import org.dspace.core.Context;
import org.dspace.rest.filter.ItemFilterUtil.BundleName;
/**
* Define the set of use cases for filtering items of interest through the REST API.
*
* @author Terry Brady, Georgetown University
*/
public class ItemFilterDefsPerm implements ItemFilterList {
protected static AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
public static final String CAT_PERM = "Perimission Filters";
private static Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemFilterDefsPerm.class);
public ItemFilterDefsPerm() {
}
public enum EnumItemFilterPermissionDefs implements ItemFilterTest {
has_restricted_original("Item has Restricted Original Bitstream",
"Item has at least one original bitstream that is not accessible to Anonymous user",
CAT_PERM) {
public boolean testItem(Context context, Item item) {
try {
for (Bundle bundle : item.getBundles()) {
if (!bundle.getName().equals(BundleName.ORIGINAL.name())) {
continue;
}
for (Bitstream bit : bundle.getBitstreams()) {
if (!authorizeService
.authorizeActionBoolean(getAnonContext(), bit, org.dspace.core.Constants.READ)) {
return true;
}
}
}
} catch (SQLException e) {
ItemFilterDefsPerm.log.warn("SQL Exception testing original bitstream access " + e.getMessage(), e);
}
return false;
}
},
has_restricted_thumbnail("Item has Restricted Thumbnail",
"Item has at least one thumbnail that is not accessible to Anonymous user", CAT_PERM) {
public boolean testItem(Context context, Item item) {
try {
for (Bundle bundle : item.getBundles()) {
if (!bundle.getName().equals(BundleName.THUMBNAIL.name())) {
continue;
}
for (Bitstream bit : bundle.getBitstreams()) {
if (!authorizeService
.authorizeActionBoolean(getAnonContext(), bit, org.dspace.core.Constants.READ)) {
return true;
}
}
}
} catch (SQLException e) {
ItemFilterDefsPerm.log
.warn("SQL Exception testing thumbnail bitstream access " + e.getMessage(), e);
}
return false;
}
},
has_restricted_metadata("Item has Restricted Metadata",
"Item has metadata that is not accessible to Anonymous user", CAT_PERM) {
public boolean testItem(Context context, Item item) {
try {
return !authorizeService
.authorizeActionBoolean(getAnonContext(), item, org.dspace.core.Constants.READ);
} catch (SQLException e) {
ItemFilterDefsPerm.log.warn("SQL Exception testing item metadata access " + e.getMessage(), e);
return false;
}
}
},;
private static Context anonContext;
private static Context getAnonContext() {
if (anonContext == null) {
anonContext = new Context();
}
return anonContext;
}
private String title = null;
private String description = null;
private EnumItemFilterPermissionDefs(String title, String description, String category) {
this.title = title;
this.description = description;
this.category = category;
}
private EnumItemFilterPermissionDefs() {
this(null, null, null);
}
public String getName() {
return name();
}
public String getTitle() {
return title;
}
public String getDescription() {
return description;
}
private String category = null;
public String getCategory() {
return category;
}
}
@Override
public ItemFilterTest[] getFilters() {
return EnumItemFilterPermissionDefs.values();
}
}

View File

@@ -1,12 +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.rest.filter;
public interface ItemFilterList {
public ItemFilterTest[] getFilters();
}

View File

@@ -1,143 +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.rest.filter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletContext;
import javax.ws.rs.WebApplicationException;
import org.apache.logging.log4j.Logger;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.authorize.service.AuthorizeService;
import org.dspace.core.Context;
import org.dspace.rest.common.Item;
import org.dspace.rest.common.ItemFilter;
/**
* The set of Item Filter Use Cases to apply to a collection of items.
*
* @author Terry Brady, Georgetown University
*/
public class ItemFilterSet {
protected AuthorizeService authorizeService = AuthorizeServiceFactory.getInstance().getAuthorizeService();
static Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemFilterSet.class);
private List<ItemFilter> itemFilters;
private ItemFilter allFiltersFilter;
/**
* Construct a set of Item Filters identified by a list string.
*
* @param filterList Comma separated list of filter names to include.
* Use {@link org.dspace.rest.common.ItemFilter#ALL} to retrieve all filters.
* @param reportItems If true, return item details. If false, return only counts of items.
*/
public ItemFilterSet(String filterList, boolean reportItems) {
log.debug(String.format("Create ItemFilterSet: %s", filterList));
itemFilters = ItemFilter.getItemFilters(filterList, reportItems);
allFiltersFilter = ItemFilter.getAllFiltersFilter(itemFilters);
}
/**
* Get the special filter that represents the intersection of all items in the Item Filter Set.
*
* @return the special Item Filter that contains items that satisfied every other Item Filter in the Item Filter Set
*/
public ItemFilter getAllFiltersFilter() {
return allFiltersFilter;
}
/**
* Evaluate an item against the use cases in the Item Filter Set.
*
* If an item satisfies all items in the Item Filter Set, it should also ve added to the special all items filter.
*
* @param context Active DSpace Context
* @param item DSpace Object to evaluate
* @param restItem REST representation of the DSpace Object being evaluated
*/
public void testItem(Context context, org.dspace.content.Item item, Item restItem) {
boolean bAllTrue = true;
for (ItemFilter itemFilter : itemFilters) {
if (itemFilter.hasItemTest()) {
bAllTrue &= itemFilter.testItem(context, item, restItem);
}
}
if (bAllTrue && allFiltersFilter != null) {
allFiltersFilter.addItem(restItem);
}
}
/**
* Get all of the Item Filters initialized into the Item Filter Set
*
* @return a list of Item Filters initialized into the Item Filter Set
*/
public List<ItemFilter> getItemFilters() {
return itemFilters;
}
/**
* Evaluate a set of Items against the Item Filters in the Item Filter Set
* Current DSpace Context
*
* @param context Current DSpace Context
* @param servletContext Context of the servlet container.
* @param childItems Collection of Items to Evaluate
* @param save If true, save the details of each item that is evaluated
* @param expand List of item details to include in the results
* @return The number of items evaluated
* @throws WebApplicationException Runtime exception for applications.
* @throws SQLException An exception that provides information on a database access error or other
* errors.
*/
public int processSaveItems(Context context, ServletContext servletContext,
Iterator<org.dspace.content.Item> childItems, boolean save, String expand)
throws WebApplicationException, SQLException {
return processSaveItems(context, servletContext, childItems, new ArrayList<Item>(), save, expand);
}
/**
* Evaluate a set of Items against the Item Filters in the Item Filter Set
*
* @param context Current DSpace Context
* @param servletContext Context of the servlet container.
* @param childItems Collection of Items to Evaluate
* @param items List of items to contain saved results
* @param save If true, save the details of each item that is evaluated
* @param expand List of item details to include in the results
* @return The number of items evaluated
* @throws WebApplicationException Runtime exception for applications.
* @throws SQLException An exception that provides information on a database access error or other
* errors.
*/
public int processSaveItems(Context context, ServletContext servletContext,
Iterator<org.dspace.content.Item> childItems, List<Item> items, boolean save,
String expand) throws WebApplicationException, SQLException {
int count = 0;
while (childItems.hasNext()) {
count++;
org.dspace.content.Item item = childItems.next();
log.debug(item.getHandle() + " evaluate.");
if (authorizeService.authorizeActionBoolean(context, item, org.dspace.core.Constants.READ)) {
Item restItem = new Item(item, servletContext, expand, context);
if (save) {
items.add(restItem);
}
testItem(context, item, restItem);
} else {
log.debug(item.getHandle() + " not authorized - not included in result set.");
}
}
return count;
}
}

View File

@@ -1,29 +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.rest.filter;
import org.dspace.content.Item;
import org.dspace.core.Context;
/**
* Item Filter Use Case Interface.
* Items will be evaluated against a set of filters.
*
* @author Terry Brady, Georgetown University
*/
public interface ItemFilterTest {
public String getName();
public String getTitle();
public String getDescription();
public String getCategory();
public boolean testItem(Context context, Item i);
}

View File

@@ -1,278 +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.rest.filter;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import com.ibm.icu.util.Calendar;
import org.apache.logging.log4j.Logger;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
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;
import org.dspace.services.factory.DSpaceServicesFactory;
public class ItemFilterUtil {
protected static ItemService itemService = ContentServiceFactory.getInstance().getItemService();
static Logger log = org.apache.logging.log4j.LogManager.getLogger(ItemFilterUtil.class);
public enum BundleName { ORIGINAL, TEXT, LICENSE, THUMBNAIL }
/**
* Default constructor
*/
private ItemFilterUtil() { }
static String[] getDocumentMimeTypes() {
return DSpaceServicesFactory.getInstance().getConfigurationService()
.getArrayProperty("rest.report-mime-document");
}
static String[] getSupportedDocumentMimeTypes() {
return DSpaceServicesFactory.getInstance().getConfigurationService()
.getArrayProperty("rest.report-mime-document-supported");
}
static String[] getSupportedImageMimeTypes() {
return DSpaceServicesFactory.getInstance().getConfigurationService()
.getArrayProperty("rest.report-mime-document-image");
}
static int countOriginalBitstream(Item item) {
return countBitstream(BundleName.ORIGINAL, item);
}
static int countBitstream(BundleName bundleName, Item item) {
int count = 0;
for (Bundle bundle : item.getBundles()) {
if (!bundle.getName().equals(bundleName.name())) {
continue;
}
count += bundle.getBitstreams().size();
}
return count;
}
static List<String> getBitstreamNames(BundleName bundleName, Item item) {
ArrayList<String> names = new ArrayList<String>();
for (Bundle bundle : item.getBundles()) {
if (!bundle.getName().equals(bundleName.name())) {
continue;
}
for (Bitstream bit : bundle.getBitstreams()) {
names.add(bit.getName());
}
}
return names;
}
static int countOriginalBitstreamMime(Context context, Item item, String[] mimeList) {
return countBitstreamMime(context, BundleName.ORIGINAL, item, mimeList);
}
static int countBitstreamMime(Context context, BundleName bundleName, Item item, String[] mimeList) {
int count = 0;
for (Bundle bundle : item.getBundles()) {
if (!bundle.getName().equals(bundleName.name())) {
continue;
}
for (Bitstream bit : bundle.getBitstreams()) {
for (String mime : mimeList) {
try {
if (bit.getFormat(context).getMIMEType().equals(mime.trim())) {
count++;
}
} catch (SQLException e) {
log.error("Get format error for bitstream " + bit.getName());
}
}
}
}
return count;
}
static int countBitstreamByDesc(BundleName bundleName, Item item, String[] descList) {
int count = 0;
for (Bundle bundle : item.getBundles()) {
if (!bundle.getName().equals(bundleName.name())) {
continue;
}
for (Bitstream bit : bundle.getBitstreams()) {
for (String desc : descList) {
String bitDesc = bit.getDescription();
if (bitDesc == null) {
continue;
}
if (bitDesc.equals(desc.trim())) {
count++;
}
}
}
}
return count;
}
static int countBitstreamSmallerThanMinSize(Context context, BundleName bundleName, Item item, String[] mimeList,
String prop) {
long size = DSpaceServicesFactory.getInstance().getConfigurationService().getLongProperty(prop);
int count = 0;
try {
for (Bundle bundle : item.getBundles()) {
if (!bundle.getName().equals(bundleName.name())) {
continue;
}
for (Bitstream bit : bundle.getBitstreams()) {
for (String mime : mimeList) {
if (bit.getFormat(context).getMIMEType().equals(mime.trim())) {
if (bit.getSizeBytes() < size) {
count++;
}
}
}
}
}
} catch (SQLException e) {
// ignore
}
return count;
}
static int countBitstreamLargerThanMaxSize(Context context, BundleName bundleName, Item item, String[] mimeList,
String prop) {
long size = DSpaceServicesFactory.getInstance().getConfigurationService().getLongProperty(prop);
int count = 0;
try {
for (Bundle bundle : item.getBundles()) {
if (!bundle.getName().equals(bundleName.name())) {
continue;
}
for (Bitstream bit : bundle.getBitstreams()) {
for (String mime : mimeList) {
if (bit.getFormat(context).getMIMEType().equals(mime.trim())) {
if (bit.getSizeBytes() > size) {
count++;
}
}
}
}
}
} catch (SQLException e) {
// ignore
}
return count;
}
static int countOriginalBitstreamMimeStartsWith(Context context, Item item, String prefix) {
return countBitstreamMimeStartsWith(context, BundleName.ORIGINAL, item, prefix);
}
static int countBitstreamMimeStartsWith(Context context, BundleName bundleName, Item item, String prefix) {
int count = 0;
try {
for (Bundle bundle : item.getBundles()) {
if (!bundle.getName().equals(bundleName.name())) {
continue;
}
for (Bitstream bit : bundle.getBitstreams()) {
if (bit.getFormat(context).getMIMEType().startsWith(prefix)) {
count++;
}
}
}
} catch (SQLException e) {
// ignore
}
return count;
}
static boolean hasUnsupportedBundle(Item item, String[] bundleList) {
if (bundleList == null) {
return false;
}
ArrayList<String> bundles = new ArrayList<String>();
for (String bundleName : bundleList) {
bundles.add(bundleName.trim());
}
for (Bundle bundle : item.getBundles()) {
if (!bundles.contains(bundle.getName())) {
return true;
}
}
return false;
}
static boolean hasOriginalBitstreamMime(Context context, Item item, String[] mimeList) {
return hasBitstreamMime(context, BundleName.ORIGINAL, item, mimeList);
}
static boolean hasBitstreamMime(Context context, BundleName bundleName, Item item, String[] mimeList) {
return countBitstreamMime(context, bundleName, item, mimeList) > 0;
}
static boolean hasMetadataMatch(Item item, String fieldList, Pattern regex) {
if (fieldList.equals("*")) {
for (MetadataValue md : itemService
.getMetadata(item, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY,
org.dspace.content.Item.ANY, org.dspace.content.Item.ANY)) {
if (regex.matcher(md.getValue()).matches()) {
return true;
}
}
} else {
for (String field : fieldList.split(",")) {
for (MetadataValue md : itemService.getMetadataByMetadataString(item, field.trim())) {
if (regex.matcher(md.getValue()).matches()) {
return true;
}
}
}
}
return false;
}
static boolean hasOnlyMetadataMatch(Item item, String fieldList, Pattern regex) {
boolean matches = false;
if (fieldList.equals("*")) {
for (MetadataValue md : itemService
.getMetadata(item, org.dspace.content.Item.ANY, org.dspace.content.Item.ANY,
org.dspace.content.Item.ANY, org.dspace.content.Item.ANY)) {
if (regex.matcher(md.getValue()).matches()) {
matches = true;
} else {
return false;
}
}
} else {
for (String field : fieldList.split(",")) {
for (MetadataValue md : itemService.getMetadataByMetadataString(item, field.trim())) {
if (regex.matcher(md.getValue()).matches()) {
matches = true;
} else {
return false;
}
}
}
}
return matches;
}
static boolean recentlyModified(Item item, int days) {
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, -days);
return cal.getTime().before(item.getLastModified());
}
}

View File

@@ -1,28 +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.utils;
import org.dspace.app.util.AbstractDSpaceWebapp;
/**
* An MBean to identify this web application.
*
* @author Bram Luyten (bram at atmire dot com)
*/
public class DSpaceWebapp
extends AbstractDSpaceWebapp {
public DSpaceWebapp() {
super("REST");
}
@Override
public boolean isUI() {
return false;
}
}

View File

@@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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/
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- Acquires the DSpace Utility Class with initialized Service Manager -->
<bean id="dspace" class="org.dspace.utils.DSpace"/>
<!-- Acquires reference to EventService -->
<bean id="dspace.eventService" factory-bean="dspace" factory-method="getEventService"/>
<!-- Inject the Default LoggerUsageEventListener into the EventService -->
<bean class="org.dspace.usage.LoggerUsageEventListener">
<property name="eventService">
<ref bean="dspace.eventService"/>
</property>
</bean>
<!-- Inject the SolrLoggerUsageEventListener into the EventService -->
<!--
Temporarily commented out SolrLoggerUsageEventListener to get REST API working.
This should be uncommented again once DS-3815 is resolved.
<bean class="org.dspace.statistics.SolrLoggerUsageEventListener">
<property name="eventService" >
<ref bean="dspace.eventService"/>
</property>
</bean>
-->
<!-- TabFileUsageEventListener -->
<!-- Uncomment to enable
<bean class="org.dspace.usage.TabFileUsageEventListener">
<property name="eventService" >
<ref bean="dspace.eventService"/>
</property>
</bean>
-->
<!--
Uncomment to enable PassiveUsageEventListener
<bean class="org.dspace.app.statistics.PassiveUsageEventListener">
<property name="eventService" >
<ref bean="dspace.eventService"/>
</property>
</bean>
-->
</beans>

View File

@@ -1,80 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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/
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:annotation-config/>
<!--
Every url in the rest will pass through these filters, login & shibboleth-login will trigger an authentication attempt.
-->
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map request-matcher="ant">
<security:filter-chain pattern="/login" filters="sif,passwordLoginAuthenticationFilter"/>
<security:filter-chain pattern="/shibboleth-login" filters="sif,passwordLoginAuthenticationFilter"/>
<security:filter-chain pattern="/logout" filters="sif,logoutFilter"/>
<security:filter-chain pattern="/**" filters="sif"/>
</security:filter-chain-map>
</bean>
<!-- Creates the spring security context object based on what was there previously -->
<bean id="sif" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
<!--Authentication filter for login -->
<bean id="passwordLoginAuthenticationFilter"
class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<!--Custom DSpace authentication manager, will handle the actual login-->
<property name="authenticationManager" ref="dspaceAuthenticationManager"/>
<!-- Ensures that after login no redirect is made to the home page, the rest will return a 200 status code -->
<property name="authenticationSuccessHandler"
ref="org.dspace.rest.authentication.NoRedirectAuthenticationLoginSuccessHandler"/>
<property name="usernameParameter" value="email"/>
<property name="passwordParameter" value="password"/>
<property name="postOnly" value="false"/>
<!--Match on any request-->
<property name="requiresAuthenticationRequestMatcher"
ref="org.springframework.security.web.util.matcher.AnyRequestMatcher"/>
</bean>
<security:authentication-manager alias="dspaceAuthenticationManager">
<security:authentication-provider ref='dspaceAuthenticationProvider'/>
</security:authentication-manager>
<!-- Custom DSpace authentication provider, this bean is responsible to login the user, it is triggered by calling the "passwordLoginAuthenticationFilter" -->
<bean class="org.dspace.rest.authentication.DSpaceAuthenticationProvider" id="dspaceAuthenticationProvider"
lazy-init="true"/>
<!--Filter for logout, destroys the spring security context-->
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg index="0" ref="org.dspace.rest.authentication.NoRedirectAuthenticationLogoutSuccessHandler"/>
<constructor-arg index="1">
<list>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
<!--Match on any request-->
<property name="logoutRequestMatcher" ref="org.springframework.security.web.util.matcher.AnyRequestMatcher"/>
</bean>
<!--Utility beans-->
<bean id="org.springframework.security.web.util.matcher.AnyRequestMatcher"
class="org.springframework.security.web.util.matcher.AnyRequestMatcher"/>
<bean id="org.dspace.rest.authentication.NoRedirectAuthenticationLoginSuccessHandler"
class="org.dspace.rest.authentication.NoRedirectAuthenticationLoginSuccessHandler"/>
<bean id="org.dspace.rest.authentication.NoRedirectAuthenticationLogoutSuccessHandler"
class="org.dspace.rest.authentication.NoRedirectAuthenticationLogoutSuccessHandler"/>
</beans>

View File

@@ -1,119 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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/
-->
<web-app id="DSpace-RESTv6" version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<filter>
<filter-name>dspace.request</filter-name>
<filter-class>org.dspace.utils.servlet.DSpaceWebappServletFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>dspace.request</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>DSpace REST API (Deprecated)</servlet-name>
<servlet-class>
org.glassfish.jersey.servlet.ServletContainer
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.dspace.rest.DSpaceRestApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DSpace REST API (Deprecated)</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
<!-- Security settings and mapping -->
<security-constraint>
<web-resource-collection>
<web-resource-name>DSpace REST API (Deprecated)</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
<!-- ConfigurationService initialization for dspace.dir -->
<context-param>
<description>
The location of the DSpace home directory
</description>
<param-name>dspace.dir</param-name>
<param-value>${dspace.dir}</param-value>
</context-param>
<context-param>
<description>
The location of the Log4J configuration
</description>
<param-name>log4jConfiguration</param-name>
<param-value>${dspace.dir}/config/log4j2.xml</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml,
/WEB-INF/security-applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.dspace.app.util.DSpaceContextListener</listener-class>
</listener>
<!-- kernel start listener (from impl)
The following listener can be used instead of the filter below, it is simpler, cleaner
and eliminates the need for a DSpaceKernelServletFilter filter to be involved with the
request cycle.
-->
<listener>
<listener-class>org.dspace.servicemanager.servlet.DSpaceKernelServletContextListener</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>org.dspace.app.util.DSpaceWebappListener</listener-class>
</listener>
</web-app>

View File

@@ -1,58 +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/
-->
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/jquery-ui.min.js"></script>
<!-- sortable.js can be obtained at http://www.kryogenix.org/code/browser/sorttable/ -->
<!-- <script src="sorttable.js"></script> -->
<script src="restReport.js"></script>
<script type="text/javascript">
var AuthReport = function() {
Report.call(this);
this.makeAuthLink = function(){return false;};
}
$(document).ready(function(){
var myReport=new AuthReport();
$("#authenticate").on("click",function(){
myReport.init();
});
$("#logout").on("click",function(){
myReport.myAuth.logout();
});
});
</script>
<script src="spin.js"></script>
<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/smoothness/jquery-ui.css"></link>
<link rel="stylesheet" type="text/css" href="restClient.css"></link>
<title>Authenticate for the REST Report Tools</title>
</head>
<body>
<h2>Login for an Authenticated Report View</h2>
<div>This is intended for sites with Password Authentication Enabled</div>
<span id="currentUser"></span>
<div id="password">
<div>
<label for="restemail">Email</label>
<input id="restemail" type="text" value="" size="30"/>
</div>
<div>
<label for="restpass">Password</label>
<input id="restpass" type="password" value=""/>
</div>
<div>
<button id="authenticate">Authenticate</button>
<button id="logout">Logout</button>
</div>
</div>
</body>
</html>

View File

@@ -1,77 +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/
-->
<!DOCTYPE html>
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/jquery-ui.min.js"></script>
<!-- sortable.js can be obtained at http://www.kryogenix.org/code/browser/sorttable/ -->
<!-- <script src="sorttable.js"></script> -->
<script src="restReport.js"></script>
<script src="restCollReport.js"></script>
<script src="spin.js"></script>
<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/smoothness/jquery-ui.css"></link>
<link rel="stylesheet" type="text/css" href="restClient.css"></link>
<title>DSpace REST QC Client</title>
</head>
<body>
<a href="query.html">Query Tool</a>
<span id="currentUser"></span>
<hr/>
<h1>DSpace REST QC Client</h1>
<div id='metadatadiv'>
<h3>Filters</h3>
<div>
<div>
<button disabled="disabled" class="activate showCollections">Show Collections</button>
</div>
<div id='filterdiv'>
</div>
<div>
<button disabled="disabled" class="activate showCollections">Show Collections</button>
</div>
</div>
<h3>Collection Report</h3>
<div>
<div><a class="this-search" href="#">URL to current search</a></div>
<div id="report">..</div>
</div>
<h3>Item Results</h3>
<div id="itemResults">
<h3>Additional data to return</h3>
<div id="queries-aux">
<button id="refresh-fields">Refresh Items</button>
<div id="show-fields"></div>
</div>
<h3>Bitstream data to return</h3>
<div id="queries-bit">
<div id="show-fields-bits"></div>
<button id="refresh-fields-bits">Refresh Items</button>
</div>
<h3>Results</h3>
<div id='itemdiv'>
<h3></h3>
<div><a class="this-search" href="#">URL to current search</a></div>
<div>
<button id="prev">Prev Page</button>
<button id="next">Next Page</button>
<button id="export">Export for Metadata Update</button>
<span id="exlimit">Export will export one page of results</span>
</div>
<input type="hidden" id="ifilter"/>
<input type="hidden" id="icollection"/>
<table id="itemtable" class="sortable"></table>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,105 +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/
-->
<html>
<head>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jqueryui/1.9.1/jquery-ui.min.js"></script>
<!-- sortable.js can be obtained at http://www.kryogenix.org/code/browser/sorttable/ -->
<!-- <script src="sorttable.js"></script> -->
<script src="restReport.js"></script>
<script src="restQueryReport.js"></script>
<script src="spin.js"></script>
<link rel="stylesheet" type="text/css" href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/smoothness/jquery-ui.css"></link>
<link rel="stylesheet" type="text/css" href="restClient.css"></link>
<title>DSpace REST Query Client</title>
</head>
<body>
<a href="index.html">Collection Filter</a>
<span id="currentUser"></span>
<hr/>
<h1>DSpace REST Query Client</h1>
<div id="querydiv">
<div id='metadatadiv'>
<h3>Collection Selector</h3>
<div id="collSelector">
</div>
<h3>Metadata Field Queries</h3>
<div>
<fieldset id="predefqueries">
<label>Pre-defined Queries</label>
<select id="predefselect">
</select>
</fieldset>
<div id="queries">
</div>
<div>
<button class="query-button" disabled="disabled" class="activate">Run Item Query</button>
</div>
</div>
<h3>Limit/Paginate Queries</h3>
<div id="queries-page">
<div>
<label for="limit">Limit:</label>
<select id="limit" name="limit">
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100" selected>100</option>
<option value="250">250</option>
<option value="1000">1000</option>
</select>
<label for="offset"> Offset:</label><input id="offset" name="offset" value="0"/>
</div>
<div>
<button class="query-button" disabled="disabled" class="activate">Run Item Query</button>
</div>
</div>
<h3>Filters</h3>
<div>
<div>
<button class="query-button" disabled="disabled" class="activate">Run Item Query</button>
</div>
<div id='filterdiv'>
</div>
<div>
<button class="query-button" disabled="disabled" class="activate">Run Item Query</button>
</div>
</div>
<h3>Additional data to return</h3>
<div id="queries-aux">
<div id="show-fields"></div>
<div>
<button class="query-button" disabled="disabled" class="activate">Run Item Query</button>
</div>
</div>
<h3>Bitstream data to return</h3>
<div id="queries-bit">
<div id="show-fields-bits"></div>
<button class="query-button" disabled="disabled" class="activate" id="refresh-fields-bit">Refresh Items</button>
</div>
<h3>Item Results</h3>
<div id='itemdiv'>
<h3></h3>
<div><a class="this-search" href="#">URL to current search</a></div>
<div>
<button id="prev">Prev Page</button>
<button id="next">Next Page</button>
<button id="export">Export for Metadata Update</button>
<span id="exlimit">Export will export one page of results, increase result limits as needed</span>
</div>
<table id="itemtable" class="sortable">
</table>
</div>
</div>
</div>
</body>
</html>

View File

@@ -1,98 +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/
*/
table {border-collapse: collapse;border-right:solid thin black;}
table td, table th {border: thin solid black; padding: 4px;}
tr.header {background-color: #EEEEEE;}
tr:hover td, tr:hover th {background-color: #DDDDDD;}
tr.even td {border-bottom: thin dotted black;}
tr.odd td {border-top: thin dotted black;}
td.even {background-color: #EEFFEE;}
td.head {background-color: #EEEEFF;}
td.num {text-align: right;}
td.link {text-decoration: underline; color: blue;}
td, th {width: 100px;}
td.error {color: red;background-color: yellow;}
td.title, th.title {width: 400px;}
td.mod, th.mod {width: 200px;}
#itemtable {width: 100%;}
#itemdiv {display: none;}
td.ititle, th.ititle {width: 600px;}
td.partial {color:red; font-style: italic;}
button:disabled {
background-color:gray;
}
input:read-only {
background-color: gray;
}
div.metadata {
padding: 2px;
width: 880px;
}
#metadatadiv select, #metadatadiv input {
padding: 2px;
margin: 4px;
}
#metadatadiv fieldset {
margin: 6px 15px;
width: 850px;
}
#metadatadiv label {
font-weight: bold;
}
#itemtable td div:not(:first-child) {
border-top: thin solid gray;
}
body {
min-height: 700px;
min-width: 700px;
}
tr.header th {
vertical-align: bottom;
}
a.partial::after {
content:" ?";
}
fieldset.catdiv {
border: thin solid black;
margin-bottom: 8px;
}
fieldset.catdiv div {
width: 380px;
float: left;
}
#collSel {
width: 90%;
}
#filterdiv label {
font-weight: normal;
}
.button {
background-color: #EEEEEE;
}
.toobig::before {
content: "*";
}
#exlimit {
font-style: italic;
}
.red {
color: red;
}

View File

@@ -1,510 +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/
*/
var CollReport = function() {
Report.call(this);
//If sortable.js is included, uncomment the following
//this.hasSorttable = function(){return true;}
this.getLangSuffix = function(){
return "[en]";
};
//Indicate if Password Authentication is supported
//this.makeAuthLink = function(){return true;};
//Indicate if Shibboleth Authentication is supported
//this.makeShibLink = function(){return true;};
this.COLL_LIMIT = 20;
this.TOOBIG = 10000;
this.loadId = 0;
this.THREADS =11;
this.THREADSP = 11;
this.ACCIDX_COLL = 1;
this.ACCIDX_ITEM = 2;
this.IACCIDX_META = 0;
this.IACCIDX_BIT = 1;
this.IACCIDX_ITEM = 2;
this.getDefaultParameters = function(){
return {
"show_fields[]" : [],
"show_fields_bits[]" : [],
filters : "",
limit : this.COUNT_LIMIT,
offset : 0,
icollection : "",
ifilter : "",
};
};
this.getCurrentParameters = function(){
return {
"show_fields[]" : this.myMetadataFields.getShowFields(),
"show_fields_bits[]" : this.myBitstreamFields.getShowFieldsBits(),
filters : this.myFilters.getFilterList(),
limit : this.myReportParameters.getLimit(),
offset : this.myReportParameters.getOffset(),
icollection : $("#icollection").val(),
ifilter : $("#ifilter").val(),
};
};
var self = this;
this.init = function() {
this.baseInit();
$("#icollection").val(self.myReportParameters.params.icollection);
$("#ifilter").val(self.myReportParameters.params.ifilter);
$("#itemResults").accordion({
heightStyle: "content",
collapsible: true,
active: 2
});
};
this.myAuth.callback = function(data) {
self.createCollectionTable();
$(".showCollections").bind("click", function(){
self.loadData();
});
$("#refresh-fields,#refresh-fields-bits").bind("click", function(){
self.drawItemTable($("#icollection").val(), $("#ifilter").val(), 0);
});
};
this.createCollectionTable = function() {
var self = this;
var tbl = $("<table/>");
tbl.attr("id","table");
$("#report").replaceWith(tbl);
var thead = $("<thead/>");
tbl.append(thead);
var tbody = $("<tbody/>");
tbl.append(tbody);
var tr = self.myHtmlUtil.addTr(thead).addClass("header");
self.myHtmlUtil.addTh(tr, "Num").addClass("num").addClass("sorttable_numeric");
self.myHtmlUtil.addTh(tr, "Community").addClass("title");
self.myHtmlUtil.addTh(tr, "Collection").addClass("title");
var thn = self.myHtmlUtil.addTh(tr, "Num Items").addClass("sorttable_numeric");
self.myHtmlUtil.makeTotalCol(thn);
thn = self.myHtmlUtil.addTh(tr, "Num Filtered").addClass("sorttable_numeric");
self.myHtmlUtil.makeTotalCol(thn);
self.addCollections();
};
this.addCollections = function() {
var self = this;
$.ajax({
url: "/rest/hierarchy",
dataType: "json",
headers: self.myAuth.getHeaders(),
success: function(data){
if (data.community != null) {
$.each(data.community, function(index, comm){
self.addCommunity(comm, comm);
});
}
self.setCollectionCounts(0);
},
error: function(xhr, status, errorThrown) {
alert("Error in /rest/hierarchy "+ status+ " " + errorThrown);
}
});
};
this.addCommunity = function(top, comm) {
var self = this;
if (comm.collection != null) {
$.each(comm.collection, function(index, coll){
self.addCollection(top, coll);
});
}
if (comm.community != null) {
$.each(comm.community, function(index, scomm){
self.addCommunity(top, scomm);
});
}
};
this.addCollection = function(top, coll) {
var self = this;
var tbody = $("#table tbody");
var index = tbody.find("tr").length;
var tr = self.myHtmlUtil.addTr(tbody);
tr.attr("cid", coll.id).attr("index",index).addClass(index % 2 == 0 ? "odd data" : "even data");
self.myHtmlUtil.addTd(tr, index + 1).addClass("num");
var parval = self.myHtmlUtil.getAnchor(top.name, self.ROOTPATH + top.handle);
self.myHtmlUtil.addTd(tr, parval).addClass("title comm");
self.myHtmlUtil.addTdAnchor(tr, coll.name, self.ROOTPATH + coll.handle).addClass("title");
};
this.setCollectionCounts = function(offset) {
var self = this;
$.ajax({
url: "/rest/filtered-collections",
data: {
limit : self.COLL_LIMIT,
offset : offset
},
dataType: "json",
headers: self.myAuth.getHeaders(),
success: function(data){
$.each(data, function(index, coll){
var id = self.getId(coll);
var tr = $("#table tbody").find("tr[cid="+id+"]");
var td = tr.find("td.numCount");
td.text(coll.numberItems);
td.on("click", function(){
self.drawItemTable(self.getId(coll),'',0);
$("#icollection").val(self.getId(coll));
$("#ifilter").val("");
});
});
//cannot assume data returned is full amount in case some items are restricted
//if (data.length == self.COLL_LIMIT) {
if (data.length > 0) {
self.setCollectionCounts(offset + self.COLL_LIMIT);
return;
}
self.myHtmlUtil.totalCol(3);
$("#table").addClass("sortable");
if (self.myFilters.getFilterList() != "") {
self.loadData();
if ($("#icollection").val() != "") {
self.drawItemTable($("#icollection").val(), $("#ifilter").val(), 0);
}
}
},
error: function(xhr, status, errorThrown) {
alert("Error in /rest/collections "+ status+ " " + errorThrown);
},
complete: function(xhr, status) {
self.spinner.stop();
$(".showCollections").attr("disabled", false);
}
});
};
this.loadData = function() {
self.spinner.spin($("h1")[0]);
$(".showCollections").attr("disabled", true);
$("#metadatadiv").accordion("option", "active", self.ACCIDX_COLL);
self.loadId++;
$("td.datacol,th.datacol").remove();
$("#table tr.data").addClass("processing");
self.myFilters.filterString = self.myFilters.getFilterList();
self.doRow(0, self.THREADS, self.loadId);
};
this.doRow = function(row, threads, curLoadId) {
if (self.loadId != curLoadId) return;
var tr = $("tr[index="+row+"]");
if (!tr.is("*")){
return;
}
var cid = tr.attr("cid");
$.ajax({
url: "/rest/filtered-collections/"+cid,
data: {
limit : self.COUNT_LIMIT,
filters : self.myFilters.filterString,
},
dataType: "json",
headers: self.myAuth.getHeaders(),
success: function(data) {
var numItems = data.numberItems;
var numItemsProcessed = data.numberItemsProcessed;
$.each(data.itemFilters, function(index, itemFilter){
if (self.loadId != curLoadId) {
return;
}
var trh = $("#table tr.header");
var filterName = itemFilter["filter-name"];
var filterTitle = itemFilter.title == null ? filterName : itemFilter.title;
if (!trh.find("th."+filterName).is("*")) {
var th = self.myHtmlUtil.addTh(trh, filterTitle);
th.addClass(filterName).addClass("datacol").addClass("sorttable_numeric");
self.myHtmlUtil.makeTotalCol(th);
if (itemFilter.description != null) {
th.attr("title", itemFilter.description);
}
$("tr.data").each(function(){
var td = self.myHtmlUtil.addTd($(this), "");
td.addClass(filterName).addClass("num").addClass("datacol");
});
}
self.setCellCount(tr, cid, 0, (numItems != numItemsProcessed), itemFilter);
self.setFilteredCount(tr, cid, 0, numItems, numItemsProcessed);
});
tr.removeClass("processing");
if (!$("#table tr.processing").is("*")) {
self.updateSortable();
self.totalFilters();
self.spinner.stop();
$(".showCollections").attr("disabled", false);
return;
}
if (row % threads == 0 || threads == 1) {
for(var i=1; i<=threads; i++) {
self.doRow(row+i, threads, curLoadId);
}
}
},
error: function(xhr, status, errorThrown) {
alert("Error in /rest/filtered-collections "+ status+ " " + errorThrown);
},
complete: function(xhr, status) {
self.spinner.stop();
$(".showCollections").attr("disabled", false);
}
});
};
this.updateSortable = function() {
if (self.hasSorttable()) {
$("#table").removeClass("sortable");
$("#table").addClass("sortable");
sorttable.makeSortable($("#table")[0]);
}
};
this.totalFilters = function() {
var colcount = $("#table tr th").length;
for(var i=4; i<colcount; i++) {
self.myHtmlUtil.totalCol(i);
}
};
this.updateRow = function(cid, offset) {
var tr = $("tr[cid="+cid+"]");
$.ajax({
url: "/rest/filtered-collections/"+cid,
data: {
limit : self.COUNT_LIMIT,
offset : offset,
filters : self.myFilters.filterString,
},
dataType: "json",
headers: self.myAuth.getHeaders(),
success: function(data) {
var numItems = data.numberItems;
var numItemsProcessed = data.numberItemsProcessed;
$.each(data.itemFilters, function(index, itemFilter){
self.setCellCount(tr, cid, offset, (numItems != numItemsProcessed + offset),itemFilter);
});
self.setFilteredCount(tr, cid, offset, numItems, numItemsProcessed);
},
error: function(xhr, status, errorThrown) {
alert("Error in /rest/filtered-collections/ " + cid+ status+ " " + errorThrown);
},
complete: function(xhr, status) {
self.spinner.stop();
$(".showCollections").attr("disabled", false);
}
});
};
this.setFilteredCount = function(tr, cid, offset, numItems, numItemsProcessed) {
var td = tr.find("td.numFiltered");
var total = numItemsProcessed + offset;
td.text(total);
td.removeClass("partial");
td.removeClass("toobig");
if (numItems != numItemsProcessed + offset) {
if (offset == 0) {
td.addClass("button");
td.off();
td.on("click", function(){
if ($(this).hasClass("toobig")) {
if (!confirm("A large number of items are present in this collection.\n\n" +
"If you choose to load this data, it will take some time to load and may impact server performance.")) {
return;
}
}
$(this).off();
$(this).removeClass("button");
self.updateRow(cid, offset + self.COUNT_LIMIT);
});
} else {
self.updateRow(cid, offset + self.COUNT_LIMIT);
}
td.addClass("partial");
var title = "Collection partially processed, item counts are incomplete. ";
if (numItems >= self.TOOBIG) {
td.addClass("toobig");
title+= "\nIt will take significant time to apply this filter to the entire collection.";
}
td.attr("title", title);
return false;
} else {
self.totalFilters();
}
return true;
};
this.setCellCount = function(tr, cid, offset, isPartial, itemFilter) {
var filterName = itemFilter["filter-name"];
var icount = itemFilter["item-count"];
var td = tr.find("td."+filterName);
if (icount == null) {
icount = 0;
}
var cur = parseInt(td.text());
if (!isNaN(cur)) {
icount += cur;
}
td.removeClass("partial");
td.removeClass("link");
td.removeAttr("title");
td.off();
td.text(icount);
if (icount != 0) {
td.addClass("link");
if (isPartial) {
td.addClass("partial");
td.attr("title", "Collection partially processed, item counts are incomplete");
}
td.on("click", function(){
self.drawItemTable(cid,filterName,0);
$("#icollection").val(cid);
$("#ifilter").val(filterName);
});
}
};
this.drawItemTable = function(cid, filter, offset) {
self = this;
self.spinner.spin($("h1")[0]);
$("#itemtable").replaceWith($('<table id="itemtable" class="sortable"></table>'));
var itbl = $("#itemtable");
//itbl.find("tr").remove("*");
var tr = self.myHtmlUtil.addTr(itbl).addClass("header");
self.myHtmlUtil.addTh(tr, "Num").addClass("num").addClass("sorttable_numeric");
self.myHtmlUtil.addTh(tr, "id");
self.myHtmlUtil.addTh(tr, "Handle");
self.myHtmlUtil.addTh(tr, "dc.title" + self.getLangSuffix()).addClass("title");
var fields = $("#show-fields select").val();
if (fields != null) {
$.each(fields, function(index, field){
self.myHtmlUtil.addTh(tr, field + self.getLangSuffix());
});
}
var bitfields = $("#show-fields-bits select").val();
if (bitfields != null) {
$.each(bitfields, function(index, bitf){
self.myHtmlUtil.addTh(tr, bitf);
});
}
var expand = "items";
if (fields != null) {
expand += ",metadata";
}
if (bitfields != null) {
expand += ",bitstreams";
}
var params = {
expand: expand,
limit: self.ITEM_LIMIT,
filters: filter,
offset: offset,
"show_fields[]" : fields,
"show_fields_bits[]" : bitfields,
};
$.ajax({
url: "/rest/filtered-collections/"+cid,
data: params,
dataType: "json",
headers: self.myAuth.getHeaders(),
success: function(data){
var source = filter == "" ? data.items : data.itemFilters[0].items;
$.each(source, function(index, item){
var tr = self.myHtmlUtil.addTr(itbl);
tr.addClass(index % 2 == 0 ? "odd data" : "even data");
self.myHtmlUtil.addTd(tr, offset+index+1).addClass("num");
self.myHtmlUtil.addTd(tr, self.getId(item));
self.myHtmlUtil.addTdAnchor(tr, item.handle, self.ROOTPATH + item.handle);
self.myHtmlUtil.addTd(tr, item.name).addClass("ititle");
if (fields != null) {
$.each(fields, function(index, field){
var td = self.myHtmlUtil.addTd(tr, "");
$.each(item.metadata, function(mindex,mv){
if (mv.key == field) {
td.append($("<div>"+mv.value+"</div>"));
}
});
});
}
if (bitfields != null) {
$.each(bitfields, function(index, bitfield){
var td = self.myHtmlUtil.addTd(tr, "");
var fieldtext = self.myBitstreamFields.getKeyText(bitfield, item, bitfields);
for(var j=0; j<fieldtext.length; j++) {
td.append($("<div>"+fieldtext[j]+"</div>"));
}
});
}
});
self.displayItems(filter + " Items in " + data.name,
offset,
self.ITEM_LIMIT,
data.numberItems,
function(){self.drawItemTable(cid, filter, (offset - self.ITEM_LIMIT < 0) ? 0 : offset - self.ITEM_LIMIT);},
function(){self.drawItemTable(cid, filter, offset + self.ITEM_LIMIT);}
);
if (self.hasSorttable()){
sorttable.makeSortable(itbl[0]);
}
$("#metadatadiv").accordion("option", "active", self.ACCIDX_ITEM);
},
error: function(xhr, status, errorThrown) {
alert("Error in /rest/filtered-collections "+ status+ " " + errorThrown);
},
complete: function(xhr, status) {
self.spinner.stop();
$(".showCollections").attr("disabled", false);
$("#itemResults").accordion("option", "active", self.IACCIDX_ITEM);
}
});
};
//Ignore the first column containing a row number and the item handle
this.exportCol = function(colnum, col) {
var data = "";
if (colnum == 0) return "";
if (colnum == 2) return "";
data += (colnum == 1) ? "" : ",";
data += self.exportCell(col);
return data;
};
};
CollReport.prototype = Object.create(Report.prototype);
$(document).ready(function(){
var myReport=new CollReport();
myReport.init();
});

View File

@@ -1,350 +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/
*/
var QueryReport = function() {
Report.call(this);
//If sortable.js is included, uncomment the following
//this.hasSorttable = function(){return true;}
this.getLangSuffix = function(){
return "[en]";
};
//Indicate if Password Authentication is supported
//this.makeAuthLink = function(){return true;};
//Indicate if Shibboleth Authentication is supported
//this.makeShibLink = function(){return true;};
this.getDefaultParameters = function(){
return {
"collSel[]" : [],
"query_field[]" : [],
"query_op[]" : [],
"query_val[]" : [],
"show_fields[]" : [],
"show_fields_bits[]" : [],
"filters" : "",
"limit" : this.ITEM_LIMIT,
"offset" : 0,
};
};
this.getCurrentParameters = function(){
var expand = "parentCollection,metadata";
if (this.myBitstreamFields.hasBitstreamFields()) {
expand += ",bitstreams";
}
var params = {
"query_field[]" : [],
"query_op[]" : [],
"query_val[]" : [],
"collSel[]" : ($("#collSel").val() == null) ? [""] : $("#collSel").val(),
limit : this.myReportParameters.getLimit(),
offset : this.myReportParameters.getOffset(),
"expand" : expand,
filters : this.myFilters.getFilterList(),
"show_fields[]" : this.myMetadataFields.getShowFields(),
"show_fields_bits[]" : this.myBitstreamFields.getShowFieldsBits(),
};
$("select.query-tool,input.query-tool").each(function() {
var paramArr = params[$(this).attr("name")];
paramArr[paramArr.length] = $(this).val();
});
return params;
};
var self = this;
this.init = function() {
this.baseInit();
};
this.initMetadataFields = function() {
this.myMetadataFields = new QueryableMetadataFields(self);
this.myMetadataFields.load();
};
this.myAuth.callback = function(data) {
$(".query-button").click(function(){self.runQuery();});
};
this.runQuery = function() {
this.spinner.spin($("body")[0]);
$("button").attr("disabled", true);
$.ajax({
url: "/rest/filtered-items",
data: this.getCurrentParameters(),
dataType: "json",
headers: self.myAuth.getHeaders(),
success: function(data){
data.metadata = $("#show-fields select").val();
data.bitfields = $("#show-fields-bits select").val();
self.drawItemFilterTable(data);
self.spinner.stop();
$("button").not("#next,#prev").attr("disabled", false);
},
error: function(xhr, status, errorThrown) {
alert("Error in /rest/filtered-items "+ status+ " " + errorThrown);
},
complete: function(xhr, status, errorThrown) {
self.spinner.stop();
$("button").not("#next,#prev").attr("disabled", false);
}
});
};
this.drawItemFilterTable = function(data) {
$("#itemtable").replaceWith($('<table id="itemtable" class="sortable"></table>'));
var itbl = $("#itemtable");
var tr = self.myHtmlUtil.addTr(itbl).addClass("header");
self.myHtmlUtil.addTh(tr, "Num").addClass("num").addClass("sorttable_numeric");
self.myHtmlUtil.addTh(tr, "id");
self.myHtmlUtil.addTh(tr, "collection");
self.myHtmlUtil.addTh(tr, "Item Handle");
self.myHtmlUtil.addTh(tr, "dc.title" + self.getLangSuffix());
var mdCols = [];
if (data.metadata) {
$.each(data.metadata, function(index, field) {
if (field != "") {
self.myHtmlUtil.addTh(tr,field + self.getLangSuffix()).addClass("returnFields");
mdCols[mdCols.length] = field;
}
});
}
if (data.bitfields) {
$.each(data.bitfields, function(index, bitfield) {
if (bitfield != "") {
self.myHtmlUtil.addTh(tr,bitfield).addClass("returnFields");
mdCols[mdCols.length] = bitfield;
}
});
}
$.each(data.items, function(index, item){
var tr = self.myHtmlUtil.addTr(itbl);
tr.addClass(index % 2 == 0 ? "odd data" : "even data");
self.myHtmlUtil.addTd(tr, self.myReportParameters.getOffset()+index+1).addClass("num");
self.myHtmlUtil.addTd(tr, self.getId(item));
if (item.parentCollection == null) {
self.myHtmlUtil.addTd(tr, "--");
} else {
self.myHtmlUtil.addTdAnchor(tr, item.parentCollection.name, self.ROOTPATH + item.parentCollection.handle);
}
self.myHtmlUtil.addTdAnchor(tr, item.handle, self.ROOTPATH + item.handle);
self.myHtmlUtil.addTd(tr, item.name);
for(var i=0; i<mdCols.length; i++) {
var key = mdCols[i];
var td = self.myHtmlUtil.addTd(tr, "");
$.each(item.metadata, function(colindex, metadata) {
if (metadata.key == key) {
if (metadata.value != null) {
var div = $("<div>"+metadata.value+"</div>");
td.append(div);
}
}
});
var fieldtext = self.myBitstreamFields.getKeyText(key, item, data.bitfields);
for(var j=0; j<fieldtext.length; j++) {
td.append($("<div>"+fieldtext[j]+"</div>"));
}
}
});
this.displayItems(data["query-annotation"],
this.myReportParameters.getOffset(),
this.myReportParameters.getLimit(),
data["unfiltered-item-count"],
function(){
self.myReportParameters.updateOffset(false);
self.runQuery();
},
function(){
self.myReportParameters.updateOffset(true);
self.runQuery();
}
);
if (this.hasSorttable()) {
sorttable.makeSortable(itbl[0]);
}
$("#metadatadiv").accordion("option", "active", $("#metadatadiv > h3").length - 1);
};
//Ignore the first column containing a row number and the item handle, get handle for the collection
this.exportCol = function(colnum, col) {
var data = "";
if (colnum == 0) return "";
if (colnum == 3) return "";
data += (colnum == 1) ? "" : ",";
if (colnum == 2) {
var anchor = $(col).find("a");
var href = anchor.is("a") ? anchor.attr("href").replace(self.ROOTPATH,"") : $(col).text();
data += "\"" + href + "\"";
} else {
data += self.exportCell(col); }
return data;
};
};
QueryReport.prototype = Object.create(Report.prototype);
$(document).ready(function(){
var myReport=new QueryReport();
myReport.init();
});
var QueryableMetadataFields = function(report) {
MetadataFields.call(this, report);
var self = this;
this.initFields = function(data, report) {
self.metadataSchemas = data;
var params = report.myReportParameters.params;
var fields = params["query_field[]"];
var ops = params["query_op[]"];
var vals = params["query_val[]"];
if (fields && ops && vals) {
if (fields.length == 0) {
self.drawFilterQuery("*","exists","");
} else {
for(var i=0; i<fields.length; i++) {
var op = ops.length > i ? ops[i] : "";
var val = vals.length > i ? vals[i] : "";
self.drawFilterQuery(fields[i],op,val);
}
}
}
self.drawShowFields(params["show_fields[]"]);
self.initQueries();
report.spinner.stop();
$(".query-button").attr("disabled", false);
};
this.initQueries = function() {
$("#predefselect")
.append($("<option value='new'>New Query</option>"))
.append($("<option value='q1'>Has No Title</option>"))
.append($("<option value='q2'>Has No dc.identifier.uri</option>"))
.append($("<option value='q3'>Has compound subject</option>"))
.append($("<option value='q4'>Has compound dc.contributor.author</option>"))
.append($("<option value='q5'>Has compound dc.creator</option>"))
.append($("<option value='q6'>Has URL in dc.description</option>"))
.append($("<option value='q7'>Has full text in dc.description.provenance</option>"))
.append($("<option value='q8'>Has non-full text in dc.description.provenance</option>"))
.append($("<option value='q9'>Has empty metadata</option>"))
.append($("<option value='q10'>Has unbreaking metadata in description</option>"))
.append($("<option value='q12'>Has XML entity in metadata</option>"))
.append($("<option value='q13'>Has non-ascii character in metadata</option>"))
.on("change",function(){
$("div.metadata").remove();
var val = $("#predefselect").val();
if (val == 'new') {
self.drawFilterQuery("","","");
} else if (val == 'q1') {
self.drawFilterQuery("dc.title","doesnt_exist","");
} else if (val == 'q2') {
self.drawFilterQuery("dc.identifier.uri","doesnt_exist","");
} else if (val == 'q3') {
self.drawFilterQuery("dc.subject.*","like","%;%");
} else if (val == 'q4') {
self.drawFilterQuery("dc.contributor.author","like","% and %");
} else if (val == 'q5') {
self.drawFilterQuery("dc.creator","like","% and %");
} else if (val == 'q6') {
self.drawFilterQuery("dc.description","matches","^.*(http://|https://|mailto:).*$");
} else if (val == 'q7') {
self.drawFilterQuery("dc.description.provenance","matches","^.*No\\. of bitstreams(.|\\r|\\n|\\r\\n)*\\.(PDF|pdf|DOC|doc|PPT|ppt|DOCX|docx|PPTX|pptx).*$");
} else if (val == 'q8') {
self.drawFilterQuery("dc.description.provenance","doesnt_match","^.*No\\. of bitstreams(.|\\r|\\n|\\r\\n)*\\.(PDF|pdf|DOC|doc|PPT|ppt|DOCX|docx|PPTX|pptx).*$");
} else if (val == 'q9') {
self.drawFilterQuery("*","matches","^\\s*$");
} else if (val == 'q10') {
self.drawFilterQuery("dc.description.*","matches","^.*[^\\s]{50,}.*$");
} else if (val == 'q12') {
self.drawFilterQuery("*","matches","^.*&#.*$");
} else if (val == 'q13') {
self.drawFilterQuery("*","matches","^.*[^[:ascii:]].*$");
}
});
};
this.drawFilterQuery = function(pField, pOp, pVal) {
var div = $("<div class='metadata'/>").appendTo("#queries");
var sel = $("<select class='query-tool' name='query_field[]'/>");
var opt = $("<option value='*'>Any Field</option>");
sel.append(opt);
$.each(self.metadataSchemas, function(index, schema){
if (schema.prefix == 'eperson') {
return;
}
$.each(schema.fields, function(findex, field) {
var name = field.name;
var parts = name.match(/^([^\.]+)\.([^\.]+)\.([^\.]+)$/);
if (parts == null) {
var wildname = name + ".*";
var opt = $("<option/>");
opt.attr("value",wildname).text(wildname);
sel.append(opt);
}
var opt = $("<option/>");
opt.attr("value",name).text(name);
sel.append(opt);
});
});
sel.val(pField);
div.append(sel);
var opsel = $("<select class='query-tool' name='query_op[]'/>");
$("<option>exists</option>").val("exists").appendTo(opsel);
$("<option>does not exist</option>").val("doesnt_exist").appendTo(opsel);
$("<option selected>equals</option>").val("equals").appendTo(opsel);
$("<option>does not equal</option>").val("not_equals").appendTo(opsel);
$("<option>like</option>").val("like").appendTo(opsel);
$("<option>not like</option>").val("not_like").appendTo(opsel);
$("<option>contains</option>").val("contains").appendTo(opsel);
$("<option>does not contain</option>").val("doesnt_contain").appendTo(opsel);
$("<option>matches</option>").val("matches").appendTo(opsel);
$("<option>does not match</option>").val("doesnt_match").appendTo(opsel);
opsel.val(pOp);
opsel.change(function(){
self.valField($(this));
});
div.append(opsel);
var input = $("<input class='query-tool' name='query_val[]'/>");
div.append(input);
input.val(pVal);
self.valField(opsel);
$("<button class='field_plus'>+</button>").appendTo(div).click(function(){
self.drawFilterQuery();
self.queryButtons();
});
$("<button class='field_minus'>-</button>").appendTo(div).click(function(){
$(this).parent("div.metadata").remove();
self.queryButtons();
});
self.queryButtons();
};
this.valField = function(valop) {
var val = valop.val();
var disableval = (val == "exists" || val == "not_exists");
var valinput = valop.parent("div.metadata").find("input[name='query_val[]']");
valinput.attr("readonly",disableval);
if (disableval) {
valinput.val("");
}
};
this.queryButtons = function() {
$("button.field_plus").attr("disabled",true);
$("button.field_plus:last").attr("disabled",false);
$("button.field_minus").attr("disabled",false);
if ($("button.field_minus").length == 1) {
$("button.field_minus").attr("disabled",true);
}
};
};
QueryableMetadataFields.prototype = Object.create(MetadataFields.prototype);

View File

@@ -1,745 +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/
*/
var Report = function() {
var self = this;
this.COLL_LIMIT = 500;
this.COUNT_LIMIT = 500;
this.ITEM_LIMIT = 100;
this.ROOTPATH = "/handle/";
//Indicate if Password Authentication is supported
this.makeAuthLink = function(){return false;};
//Indicate if Shibboleth Authentication is supported
this.makeShibLink = function(){return false;};
this.shibPath = "/Shibboleth.sso/Login";
//Override this to return obj.id for DSpace 5 versions
this.getId = function(obj) {
return obj.uuid;
};
//Override this method is sortable.js has been included
this.hasSorttable = function() {
return false;
};
this.getDefaultParameters = function(){
return {};
};
this.getCurrentParameters = function(){
return {};
};
this.saveUrl = function() {
this.myReportParameters.saveAsUrl(this.getCurrentParameters());
};
this.getLoginPayload = function() {
//Placeholder to allow a customized report to prompt for email/password
//If not enabled, the authenticaton callback will be called immediately
var email = $("#restemail").val();
var pass = $("#restpass").val();
if (email == "" || pass == "") {
return undefined;
} else if (email == null || pass == null) {
return undefined;
} else {
return {email: email, password: pass};
}
};
this.getLangSuffix = function(){
return "";
};
this.myAuth = new Auth(this);
this.myAuth.authStat();
this.myAuth.callback = function(data) {
self.spinner.stop();
};
this.myHtmlUtil = new HtmlUtil();
this.spinner = new Spinner({
lines: 13, // The number of lines to draw
length: 20, // The length of each line
width: 10, // The line thickness
radius: 30, // The radius of the inner circle
corners: 1, // Corner roundness (0..1)
rotate: 0, // The rotation offset
direction: 1, // 1: clockwise, -1: counterclockwise
color: '#000', // #rgb or #rrggbb or array of colors
speed: 1, // Rounds per second
trail: 60, // Afterglow percentage
shadow: false, // Whether to render a shadow
hwaccel: false, // Whether to use hardware acceleration
className: 'spinner', // The CSS class to assign to the spinner
zIndex: 2e9, // The z-index (defaults to 2000000000)
top: '400px', // Top position relative to parent
left: '600px' // Left position relative to parent
});
this.displayItems = function(itemsTitle, offset, limit, total, funcdec, funcinc) {
var count = $("#itemtable tr.data").length;
var last = offset + limit;
var suff = "";
if (total == null) {
last = offset + count;
suff = (count == limit) ? " of " + last + "+ " : " of " + last;
} else if (limit == total) {
//total may only be accurate to page size
suff = " of " + total + "+ ";
} else {
last = (last > total) ? total : last;
suff = " of " + total;
}
suff += " unfiltered; displaying " + count + " filtered" ;
itemsTitle += " (" + (offset+1) + " - " + last + suff + ")";
$("#prev,#next").attr("disabled",true);
$("#itemdiv h3").text(itemsTitle);
$("#exlimit").removeClass("red");
if (offset > 0) $("#prev").attr("disabled", false);
$("#prev").off("click").on("click", funcdec);
//in case of filters, always allow next
if (total == null) {
$("#next").attr("disabled", false);
} else if (offset + limit < total) {
$("#next").attr("disabled", false);
$("#exlimit").addClass("red");
} else if (limit == total) {
//total may only be accurate to one page
$("#next").attr("disabled", false);
$("#exlimit").addClass("red");
}
$("#next").off("click").on("click", funcinc);
};
this.myReportParameters = undefined;
this.myFilters = undefined;
this.myMetadataFields = undefined;
this.initMetadataFields = function() {
this.myMetadataFields = new MetadataFields(self);
this.myMetadataFields.load();
};
this.initBitstreamFields = function() {
this.myBitstreamFields = new BitstreamFields(self);
this.myBitstreamFields.load();
};
this.baseInit = function() {
this.myReportParameters = new ReportParameters(
this.getDefaultParameters(),
window.location.search.substr(1)
);
this.spinner.spin($("h1")[0]);
this.myFilters = new Filters(this.myReportParameters.params["filters"]);
this.initMetadataFields();
this.initBitstreamFields();
this.getActiveTab = function(){return 1;};
$("#metadatadiv").accordion({
heightStyle: "content",
collapsible: true,
active: self.getActiveTab()
});
$("#export").click(function(){
self.export($("#itemtable tr"));
});
$("a.this-search").on("click",function(){
self.saveUrl();
});
this.myFilters.createFilterTable(this.myReportParameters.params.filters);
this.myAuth.init();
};
this.makeCsv = function(rows) {
var itemdata = "";
rows.each(function(rownum, row){
itemdata += (rownum == 0) ? "" : "\r\n";
$(row).find("td,th").each(function(colnum, col){
itemdata += self.exportCol(colnum, col);
});
});
return itemdata;
};
this.export = function(rows) {
var itemdata = "data:text/csv;charset=utf-8," + this.makeCsv(rows);
var encodedUri = encodeURI(itemdata);
window.open(encodedUri);
};
//this is meant to be overridden for each report
this.exportCol = function(colnum, col) {
var data = "";
data += (colnum == 0) ? "" : ",";
data += self.exportCell(col);
return data;
};
this.exportCell = function(col) {
data = "\"";
$(col).contents().each(function(i, node){
if ($(node).is("hr")) {
data += "||";
} else {
data += $(node).text().replace(/\n/g," ").replace(/"/g,"\"\"").replace(/\s/g," ");
if ($(node).is("div:not(:last-child)")) {
data += "||";
}
}
});
data += "\"";
return data;
};
this.init = function() {
this.baseInit();
};
};
var Auth = function(report) {
this.report = report;
this.TOKEN = undefined;
this.callback = function(data) {
};
this.saveToken = function(data) {
this.TOKEN = data;
};
this.init = function() {
var loginPayload = report.getLoginPayload();
if (loginPayload == undefined) {
this.callback();
return;
}
var self = this;
$.ajax({
url : "/rest/login",
contentType : "application/x-www-form-urlencoded",
accepts : "application/json",
type : "POST",
data : loginPayload,
success : function(data){
self.saveToken(data);
},
error: function(xhr, status, errorThrown) {
alert("Error in /rest/login "+ status+ " " + errorThrown);
},
complete: function(xhr, status) {
self.authStat();
self.callback();
}
});
};
this.verifyShibLogin = function() {
var self = this;
$.ajax({
url: "/rest/shibboleth-login",
success: self.authStat
});
};
this.authStat = function() {
var self = this;
$.ajax({
url : "/rest/status",
dataType : "json",
error: function(xhr, status, errorThrown) {
alert("Error in /rest/status "+ status+ " " + errorThrown);
},
success: function(data) {
var user = "";
if (data.email != undefined) {
user = data.email;
} else {
user = "You are not logged in. Some items may be excluded from reports.";
}
var anchor = $("<a/>").text(user);
if (self.report.makeShibLink()) {
anchor.attr("href", self.report.shibPath + "?target="+document.location);
}
if (self.report.makeAuthLink()) {
anchor.attr("href","javascript:window.open('authenticate.html','Authenticate (Password Auth Only)','height=200,width=500')");
}
$("#currentUser").empty().append("<b>Current User: </b>").append(anchor);
if (data.email == undefined && self.report.makeShibLink()) {
self.verifyShibLogin();
}
}
});
};
this.logout = function() {
var self = this;
$.ajax({
url : "/rest/logout",
error: function(xhr, status, errorThrown) {
alert("Error in /rest/logout "+ status+ " " + errorThrown);
},
complete: function(xhr, status) {
self.authStat();
}
});
};
this.getHeaders = function() {
var HEADERS = {};
if (this.TOKEN != null) {
HEADERS['rest-dspace-token'] = this.TOKEN;
}
return HEADERS;
};
};
var ReportParameters = function(defaultParams, prmstr) {
this.params = defaultParams;
if (prmstr == null) prmstr = "";
var prmarr = prmstr.split("&");
for ( var i = 0; i < prmarr.length; i++) {
var tmparr = prmarr[i].split("=");
var field = tmparr[0];
var val = decodeURIComponent(tmparr[1]);
var pval = this.params[field];
if ($.isArray(pval)) {
pval[pval.length] = val;
} else {
this.params[field] = val;
}
}
$("#limit").val(this.params.limit);
$("#offset").val(this.params.offset);
this.limit = this.params.limit;
this.offset = this.params.offset;
this.getOffset = function() {
var offset = $("#offset").val();
return $.isNumeric(offset) ? Number(offset) : this.offset;
};
this.getNextOffset = function() {
return this.getOffset() + this.getLimit();
};
this.getPrevOffset = function() {
var v = this.getOffset() - this.getLimit();
return v < 0 ? 0 : v;
};
this.getLimit = function() {
var limit = $("#limit").val();
return $.isNumeric(limit) ? Number(limit) : this.limit;
};
this.updateOffset = function(increment) {
var val = $("#offset").val();
var lim = $("#limit").val();
if ($.isNumeric(val) && $.isNumeric(lim)) {
if (increment) {
$("#offset").val(this.getNextOffset());
} else {
$("#offset").val(this.getPrevOffset());
}
}
};
this.saveAsUrl = function(params) {
var pstr = $.param(params).replace(/%5B%5D/g,"[]");
window.location.search = pstr;
};
};
var Filters = function() {
this.createFilterTable = function(filterList) {
self = this;
var paramFilterSel = filterList == null ? new Array() : filterList.split(",");
var categories = new Array();
self.addFilter("", categories, "General", "None", "De-select all filters", "none").click(
function(){
$("input.filter,input.all").attr("checked",false);
$("#filter-reload").attr("disabled", false);
}
);
self.addFilter("all", categories, "General", "All", "Show all filters", "all").click(
function(){
$("input.filter,input.none").attr("checked",false);
$("#filter-reload").attr("disabled", false);
}
);
$.getJSON(
"/rest/filters",
function(data){
$.each(data, function(index, filter){
var checkbox = self.addFilter(filter["filter-name"], categories, filter.category, filter.title, filter.description, "filter").click(
function(){
$("input.none,input.all").attr("checked",false);
$("#filter-reload").attr("disabled", false);
}
);
$.each(paramFilterSel, function(index, filtername){
if (filtername == filter["filter-name"]) {
checkbox.attr("checked", true);
}
});
});
}
);
};
this.addFilter = function(val, categories, category, title, description, cname) {
var catdiv = null;
for(var i=0; i<categories.length; i++) {
if (categories[i].name == category) {
catdiv = categories[i].div;
break;
}
}
if (catdiv == null) {
catdiv = $("<fieldset class='catdiv'/>");
catdiv.append($("<legend>"+category+"</legend>"));
$("#filterdiv").append(catdiv);
categories[categories.length] = {name: category, div: catdiv};
}
var div = $("<div/>");
var input = $("<input name='filters[]' type='checkbox'/>");
input.attr("id",val);
input.val(val);
input.addClass(cname);
div.append(input);
var ftitle = (title == null) ? val : title;
var label = $("<label>" + ftitle + "</label>");
label.attr("title", description);
div.append(label);
catdiv.append(div);
return input;
};
this.getFilterList = function() {
var list="";
$("input:checked[name='filters[]']").each(
function(){
if (list != "") {
list += ",";
}
list += $(this).val();
}
);
if (list == "") {
list = "none";
}
return list;
};
};
var MetadataFields = function(report) {
this.metadataSchemas = undefined;
var self = this;
this.load = function(){
$.ajax({
url: "/rest/registries/schema",
dataType: "json",
success: function(data){
self.initFields(data, report);
},
error: function(xhr, status, errorThrown) {
alert("Error in /rest/registries/schema "+ status+ " " + errorThrown);
},
complete: function(xhr, status) {
}
});
};
this.initFields = function(data, report) {
var params = report.myReportParameters.params;
self.metadataSchemas = data;
self.drawShowFields(params["show_fields[]"]);
};
this.getShowFields = function(){
var val = $("#show-fields select").val();
return val == null ? Array() : val;
};
this.drawShowFields = function(pfields) {
var sel = $("<select name='show_fields'/>").attr("multiple","true").attr("size","8").appendTo("#show-fields");
$.each(this.metadataSchemas, function(index, schema){
if (schema.prefix == 'eperson') {
return;
}
$.each(schema.fields, function(findex, field) {
var name = field.name;
var opt = $("<option/>");
opt.attr("value",name).text(name);
for(var i=0; i<pfields.length; i++) {
if (pfields[i] == name) {
opt.attr("selected", true);
}
}
sel.append(opt);
});
});
};
this.initQueries = function(){};
};
var BitstreamFields = function(report) {
var self = this;
this.isOriginal = function(bit){
return bit.bundleName === "ORIGINAL";
};
this.map = [
{
key: "original-file-names",
name: "Original File Names",
ftest: self.isOriginal,
fval: function(bit) {
return bit.name;
}
},
{
key: "mime-type",
name: "Mime Type",
ftest: self.isOriginal,
fval: function(bit) {
return bit.mimeType;
}
},
{
key: "bitstream-format",
name: "Bitstream Format",
ftest: self.isOriginal,
fval: function(bit) {
return bit.format;
}
},
{
key: "bitstream-description",
name: "Bitstream Description",
ftest: self.isOriginal,
fval: function(bit) {
return bit.description;
}
},
{
key: "bitstream-size",
name: "Bitstream Size",
ftest: self.isOriginal,
fval: function(bit) {
return Number(bit.sizeBytes);
}
},
{
key: "bitstream-checksum",
name: "MD5 Checksum",
ftest: self.isOriginal,
fval: function(bit) {
if (bit.checkSum.checkSumAlgorithm === "MD5") {
return bit.checkSum.value;
}
return "";
}
},
];
this.load = function(){
self.initFields(report);
};
this.initFields = function(report) {
var params = report.myReportParameters.params;
self.drawShowFieldsBits(params["show_fields_bits[]"]);
};
this.hasBitstreamFields = function() {
return self.getShowFieldsBits() != null;
};
this.getShowFieldsBits = function(){
var val = $("#show-fields-bits select").val();
return val == null ? Array() : val;
};
this.drawShowFieldsBits = function(pfieldsBits) {
var sel = $("<select name='show_fields_bits'/>");
sel.attr("multiple","true").attr("size","8").appendTo("#show-fields-bits");
for(var i=0; i<this.map.length; i++) {
var opt = report.myHtmlUtil.addOpt(sel, this.map[i].name, this.map[i].key);
if (pfieldsBits != null) {
opt.attr("selected", pfieldsBits[this.map[i].key] != undefined ? "Y" : null);
}
sel.append(opt);
}
};
this.getKeyText = function(key, item, bitfields) {
var ret = [];
if (bitfields == null || item.bitstreams == null) {
return ret;
}
if (!bitfields.includes(key)) {
return ret;
}
var mapval = null;
for(var i=0; i<this.map.length; i++) {
if (this.map[i].key === key) {
mapval = this.map[i];
break;
}
}
if (mapval == null) {
return ret;
}
$.each(item.bitstreams, function(colindex, bitstream) {
if (mapval.ftest(bitstream)) {
var val = mapval.fval(bitstream);
if (val != null) {
if (isNaN(val) || ret.length == 0) {
ret.push(val);
} else {
ret[0] += val;
}
}
}
});
return ret;
};
};
var HtmlUtil = function() {
this.addTr = function(tbl) {
var tr = $("<tr/>");
tbl.append(tr);
return tr;
};
this.addTd = function(tr, val) {
var td = $("<td/>");
if (val != null) {
td.append(val);
}
tr.append(td);
return td;
};
this.addTh = function(tr, val) {
var th = $("<th/>");
if (val != null) {
th.append(val);
}
tr.append(th);
return th;
};
this.addTdAnchor = function(tr, val, href) {
return this.addTd(tr, this.getAnchor(val, href));
};
this.getAnchor = function(val, href) {
var a = $("<a/>");
a.append(val);
a.attr("href", href);
a.attr("target", "_blank");
a.attr("rel", "noopener noreferrer");
return a;
};
this.createOpt = function(name, val) {
var opt = $("<option/>");
opt.attr("value", val).text(name);
return opt;
};
this.addOpt = function(sel, name, val) {
var opt = this.createOpt(name, val);
sel.append(opt);
return opt;
};
this.addDisabledOpt = function(sel, name, val) {
var opt = this.createOpt(name, val).attr("disabled",true);
sel.append(opt);
return opt;
};
this.makeTotalCol = function(th) {
th.append($("<hr><span class='num'>-</span>"));
};
this.totalCol = function(index){
var total = 0;
$("#table tr.data").each(function(){
var val = $($(this).find("td")[index]).text();
if ($.isNumeric(val)) {
total += Number(val);
}
});
$($("#table tr.header th")[index]).find("span.num").text(total);
};
};
var CommunitySelector = function(report, parent, paramCollSel) {
var self = this;
var collSel = $("<select/>").attr("id","collSel").attr("name","collSel").attr("multiple", true).attr("size",15);
parent.append(collSel);
report.myHtmlUtil.addOpt(collSel, "Whole Repository", "");
$.ajax({
url: "/rest/hierarchy",
dataType: "json",
headers: report.myAuth.getHeaders(),
success: function(data){
var collSel = $("#collSel");
if (data.community != null) {
$.each(data.community, function(index, comm){
self.addCommLabel(collSel, comm, 0, paramCollSel);
});
}
},
error: function(xhr, status, errorThrown) {
alert("Error in /rest/communities "+ status+ " " + errorThrown);
},
complete: function(xhr, status) {
}
});
this.addCommLabel = function(collSel, comm, indent, paramCollSel) {
var prefix = "";
for(var i=0; i<indent; i++) {
prefix += "--";
}
report.myHtmlUtil.addDisabledOpt(collSel, prefix + comm.name, comm.id);
if (comm.collection != null) {
$.each(comm.collection, function(index, coll) {
var opt = report.myHtmlUtil.addOpt(collSel, prefix + "--" + coll.name, coll.id);
$.each(paramCollSel, function(index, collid){
if (collid == coll.id) {
opt.attr("selected", true);
}
});
});
}
if (comm.community != null) {
$.each(comm.community, function(index, scomm) {
self.addCommLabel(collSel, scomm, indent + 1, paramCollSel);
});
}
};
};

View File

@@ -1,369 +0,0 @@
/**
* Copyright (c) 2011-2014 Felix Gnass
* Licensed under the MIT license
*/
/*
* The MIT License
Copyright (c) 2011-2014 Felix Gnass [fgnass at neteye dot de]
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
(function(root, factory) {
/* CommonJS */
if (typeof exports == 'object') module.exports = factory();
/* AMD module */
else if (typeof define == 'function' && define.amd) define(factory);
/* Browser global */
else root.Spinner = factory();
}
(this, function() {
"use strict";
var prefixes = ['webkit', 'Moz', 'ms', 'O'] /* Vendor prefixes */
, animations = {} /* Animation rules keyed by their name */
, useCssAnimations /* Whether to use CSS animations or setTimeout */
;
/**
* Utility function to create elements. If no tag name is given,
* a DIV is created. Optionally properties can be passed.
*/
function createEl(tag, prop) {
var el = document.createElement(tag || 'div')
, n
;
for(n in prop) el[n] = prop[n];
return el;
}
/**
* Appends children and returns the parent.
*/
function ins(parent /* child1, child2, ...*/) {
for (var i=1, n=arguments.length; i<n; i++)
parent.appendChild(arguments[i])
return parent;
}
/**
* Insert a new stylesheet to hold the @keyframe or VML rules.
*/
var sheet = (function() {
var el = createEl('style', {type : 'text/css'});
ins(document.getElementsByTagName('head')[0], el);
return el.sheet || el.styleSheet;
}());
/**
* Creates an opacity keyframe animation rule and returns its name.
* Since most mobile Webkits have timing issues with animation-delay,
* we create separate rules for each line/segment.
*/
function addAnimation(alpha, trail, i, lines) {
var name = ['opacity', trail, ~~(alpha*100), i, lines].join('-')
, start = 0.01 + i/lines * 100
, z = Math.max(1 - (1-alpha) / trail * (100-start), alpha)
, prefix = useCssAnimations.substring(0, useCssAnimations.indexOf('Animation')).toLowerCase()
, pre = prefix && '-' + prefix + '-' || ''
;
if (!animations[name]) {
sheet.insertRule(
'@' + pre + 'keyframes ' + name + '{' +
'0%{opacity:' + z + '}' +
start + '%{opacity:' + alpha + '}' +
(start+0.01) + '%{opacity:1}' +
(start+trail) % 100 + '%{opacity:' + alpha + '}' +
'100%{opacity:' + z + '}' +
'}', sheet.cssRules.length);
animations[name] = 1;
}
return name;
}
/**
* Tries various vendor prefixes and returns the first supported property.
*/
function vendor(el, prop) {
var s = el.style
, pp
, i
;
prop = prop.charAt(0).toUpperCase() + prop.slice(1);
for(i=0; i<prefixes.length; i++) {
pp = prefixes[i]+prop;
if(s[pp] !== undefined) return pp;
}
if(s[prop] !== undefined) return prop;
}
/**
* Sets multiple style properties at once.
*/
function css(el, prop) {
for (var n in prop)
el.style[vendor(el, n)||n] = prop[n];
return el;
}
/**
* Fills in default values.
*/
function merge(obj) {
for (var i=1; i < arguments.length; i++) {
var def = arguments[i];
for (var n in def)
if (obj[n] === undefined) obj[n] = def[n];
}
return obj;
}
/**
* Returns the line color from the given string or array.
*/
function getColor(color, idx) {
return typeof color == 'string' ? color : color[idx % color.length];
}
// Built-in defaults
var defaults = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 5, // The line thickness
radius: 10, // The radius of the inner circle
rotate: 0, // Rotation offset
corners: 1, // Roundness (0..1)
color: '#000', // #rgb or #rrggbb
direction: 1, // 1: clockwise, -1: counterclockwise
speed: 1, // Rounds per second
trail: 100, // Afterglow percentage
opacity: 1/4, // Opacity of the lines
fps: 20, // Frames per second when using setTimeout()
zIndex: 2e9, // Use a high z-index by default
className: 'spinner', // CSS class to assign to the element
top: '50%', // center vertically
left: '50%', // center horizontally
position: 'absolute' // element position
};
/** The constructor */
function Spinner(o) {
this.opts = merge(o || {}, Spinner.defaults, defaults);
}
// Global defaults that override the built-ins:
Spinner.defaults = {};
merge(Spinner.prototype, {
/**
* Adds the spinner to the given target element. If this instance is already
* spinning, it is automatically removed from its previous target b calling
* stop() internally.
*/
spin: function(target) {
this.stop();
var self = this
, o = self.opts
, el = self.el = css(createEl(0, {className: o.className}), {position: o.position, width: 0, zIndex: o.zIndex})
;
css(el, {
left: o.left,
top: o.top
});
if (target) {
target.insertBefore(el, target.firstChild||null);
}
el.setAttribute('role', 'progressbar');
self.lines(el, self.opts);
if (!useCssAnimations) {
// No CSS animation support, use setTimeout() instead
var i = 0
, start = (o.lines - 1) * (1 - o.direction) / 2
, alpha
, fps = o.fps
, f = fps/o.speed
, ostep = (1-o.opacity) / (f*o.trail / 100)
, astep = f/o.lines
;(function anim() {
i++;
for (var j = 0; j < o.lines; j++) {
alpha = Math.max(1 - (i + (o.lines - j) * astep) % f * ostep, o.opacity);
self.opacity(el, j * o.direction + start, alpha, o);
}
self.timeout = self.el && setTimeout(anim, ~~(1000/fps));
})();
}
return self;
},
/**
* Stops and removes the Spinner.
*/
stop: function() {
var el = this.el;
if (el) {
clearTimeout(this.timeout);
if (el.parentNode) el.parentNode.removeChild(el);
this.el = undefined;
}
return this;
},
/**
* Internal method that draws the individual lines. Will be overwritten
* in VML fallback mode below.
*/
lines: function(el, o) {
var i = 0
, start = (o.lines - 1) * (1 - o.direction) / 2
, seg
;
function fill(color, shadow) {
return css(createEl(), {
position: 'absolute',
width: (o.length+o.width) + 'px',
height: o.width + 'px',
background: color,
boxShadow: shadow,
transformOrigin: 'left',
transform: 'rotate(' + ~~(360/o.lines*i+o.rotate) + 'deg) translate(' + o.radius+'px' +',0)',
borderRadius: (o.corners * o.width>>1) + 'px'
});
}
for (; i < o.lines; i++) {
seg = css(createEl(), {
position: 'absolute',
top: 1+~(o.width/2) + 'px',
transform: o.hwaccel ? 'translate3d(0,0,0)' : '',
opacity: o.opacity,
animation: useCssAnimations && addAnimation(o.opacity, o.trail, start + i * o.direction, o.lines) + ' ' + 1/o.speed + 's linear infinite'
});
if (o.shadow) ins(seg, css(fill('#000', '0 0 4px ' + '#000'), {top: 2+'px'}));
ins(el, ins(seg, fill(getColor(o.color, i), '0 0 1px rgba(0,0,0,.1)')));
}
return el;
},
/**
* Internal method that adjusts the opacity of a single line.
* Will be overwritten in VML fallback mode below.
*/
opacity: function(el, i, val) {
if (i < el.childNodes.length) el.childNodes[i].style.opacity = val;
}
});
function initVML() {
/* Utility function to create a VML tag */
function vml(tag, attr) {
return createEl('<' + tag + ' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">', attr);
}
// No CSS transforms but VML support, add a CSS rule for VML elements:
sheet.addRule('.spin-vml', 'behavior:url(#default#VML)');
Spinner.prototype.lines = function(el, o) {
var r = o.length+o.width
, s = 2*r
;
function grp() {
return css(
vml('group', {
coordsize: s + ' ' + s,
coordorigin: -r + ' ' + -r
}),
{ width: s, height: s }
);
}
var margin = -(o.width+o.length)*2 + 'px'
, g = css(grp(), {position: 'absolute', top: margin, left: margin})
, i
;
function seg(i, dx, filter) {
ins(g,
ins(css(grp(), {rotation: 360 / o.lines * i + 'deg', left: ~~dx}),
ins(css(vml('roundrect', {arcsize: o.corners}), {
width: r,
height: o.width,
left: o.radius,
top: -o.width>>1,
filter: filter
}),
vml('fill', {color: getColor(o.color, i), opacity: o.opacity}),
vml('stroke', {opacity: 0}) // transparent stroke to fix color bleeding upon opacity change
)
)
);
}
if (o.shadow)
for (i = 1; i <= o.lines; i++)
seg(i, -2, 'progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)');
for (i = 1; i <= o.lines; i++) seg(i);
return ins(el, g);
};
Spinner.prototype.opacity = function(el, i, val, o) {
var c = el.firstChild;
o = o.shadow && o.lines || 0;
if (c && i+o < c.childNodes.length) {
c = c.childNodes[i+o]; c = c && c.firstChild; c = c && c.firstChild;
if (c) c.opacity = val;
}
};
}
var probe = css(createEl('group'), {behavior: 'url(#default#VML)'});
if (!vendor(probe, 'transform') && probe.adj) initVML();
else useCssAnimations = vendor(probe, 'animation');
return Spinner;
}));

View File

@@ -1,68 +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.rest.common;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.io.Writer;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
public class TestJAXBSchema {
private static class TestSchemaOutputResolver extends SchemaOutputResolver {
private final Writer output;
public TestSchemaOutputResolver(Writer output) {
this.output = output;
}
public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
StreamResult result = new StreamResult(output);
result.setSystemId("xsd0.xsd");
return result;
}
}
@Test
public void testFullSchema() throws Exception {
StringWriter writer = new StringWriter();
TestSchemaOutputResolver resolver = new TestSchemaOutputResolver(writer);
JAXBContext context = JAXBContext.newInstance(
Bitstream.class,
CheckSum.class,
Collection.class,
Community.class,
DSpaceObject.class,
Item.class,
MetadataEntry.class,
ResourcePolicy.class,
Status.class
);
context.generateSchema(resolver);
String res = "org/dspace/rest/common/expected_xsd0.xsd";
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(res);
String expected = IOUtils.toString(is, "UTF-8");
// System.err.println(writer.toString());
assertEquals("JAXB schema", expected, writer.toString());
}
}

View File

@@ -1,154 +0,0 @@
<?xml version="1.0" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="bitstream" type="bitstream"/>
<xs:element name="collection" type="collection"/>
<xs:element name="community" type="community"/>
<xs:element name="dspaceobject" type="dSpaceObject"/>
<xs:element name="item" type="item"/>
<xs:element name="metadataentry" type="metadataEntry"/>
<xs:element name="resourcepolicy" type="resourcePolicy"/>
<xs:element name="status" type="status"/>
<xs:complexType name="bitstream">
<xs:complexContent>
<xs:extension base="dSpaceObject">
<xs:sequence>
<xs:element name="bundleName" type="xs:string" minOccurs="0"/>
<xs:element name="checkSum" type="checkSum" minOccurs="0"/>
<xs:element name="description" type="xs:string" minOccurs="0"/>
<xs:element name="format" type="xs:string" minOccurs="0"/>
<xs:element name="mimeType" type="xs:string" minOccurs="0"/>
<xs:element name="parentObject" type="dSpaceObject" minOccurs="0"/>
<xs:element name="policies" type="resourcePolicy" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="retrieveLink" type="xs:string" minOccurs="0"/>
<xs:element name="sequenceId" type="xs:int" minOccurs="0"/>
<xs:element name="sizeBytes" type="xs:long" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="dSpaceObject">
<xs:sequence>
<xs:element name="link" type="xs:string"/>
<xs:element name="expand" type="xs:string" maxOccurs="unbounded"/>
<xs:element name="handle" type="xs:string" minOccurs="0"/>
<xs:element name="name" type="xs:string" minOccurs="0"/>
<xs:element name="type" type="xs:string" minOccurs="0"/>
<xs:element name="UUID" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="checkSum">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="checkSumAlgorithm" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
<xs:complexType name="resourcePolicy">
<xs:sequence>
<xs:element name="action" type="action" minOccurs="0"/>
<xs:element name="endDate" type="xs:dateTime" minOccurs="0"/>
<xs:element name="epersonId" type="xs:string" minOccurs="0"/>
<xs:element name="groupId" type="xs:string" minOccurs="0"/>
<xs:element name="id" type="xs:int" minOccurs="0"/>
<xs:element name="resourceId" type="xs:string" minOccurs="0"/>
<xs:element name="resourceType" type="xs:string" minOccurs="0"/>
<xs:element name="rpDescription" type="xs:string" minOccurs="0"/>
<xs:element name="rpName" type="xs:string" minOccurs="0"/>
<xs:element name="rpType" type="xs:string" minOccurs="0"/>
<xs:element name="startDate" type="xs:dateTime" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="collection">
<xs:complexContent>
<xs:extension base="dSpaceObject">
<xs:sequence>
<xs:element name="copyrightText" type="xs:string" minOccurs="0"/>
<xs:element name="introductoryText" type="xs:string" minOccurs="0"/>
<xs:element name="items" type="item" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="license" type="xs:string" minOccurs="0"/>
<xs:element name="numberItems" type="xs:int" minOccurs="0"/>
<xs:element name="parentCommunity" type="community" minOccurs="0"/>
<xs:element name="parentCommunityList" type="community" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="shortDescription" type="xs:string" minOccurs="0"/>
<xs:element name="sidebarText" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="item">
<xs:complexContent>
<xs:extension base="dSpaceObject">
<xs:sequence>
<xs:element name="archived" type="xs:string" minOccurs="0"/>
<xs:element name="bitstreams" type="bitstream" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="lastModified" type="xs:string" minOccurs="0"/>
<xs:element name="metadata" type="metadataEntry" maxOccurs="unbounded"/>
<xs:element name="parentCollection" type="collection" minOccurs="0"/>
<xs:element name="parentCollectionList" type="collection" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="parentCommunityList" type="community" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="withdrawn" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="metadataEntry">
<xs:sequence>
<xs:element name="key" type="xs:string" minOccurs="0"/>
<xs:element name="language" type="xs:string" minOccurs="0"/>
<xs:element name="value" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="community">
<xs:complexContent>
<xs:extension base="dSpaceObject">
<xs:sequence>
<xs:element name="collections" type="collection" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="copyrightText" type="xs:string" minOccurs="0"/>
<xs:element name="countItems" type="xs:int" minOccurs="0"/>
<xs:element name="introductoryText" type="xs:string" minOccurs="0"/>
<xs:element name="logo" type="bitstream" minOccurs="0"/>
<xs:element name="parentCommunity" type="community" minOccurs="0"/>
<xs:element name="shortDescription" type="xs:string" minOccurs="0"/>
<xs:element name="sidebarText" type="xs:string" minOccurs="0"/>
<xs:element name="subcommunities" type="community" maxOccurs="unbounded"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="status">
<xs:sequence>
<xs:element name="apiVersion" type="xs:string" minOccurs="0"/>
<xs:element name="authenticated" type="xs:boolean"/>
<xs:element name="email" type="xs:string" minOccurs="0"/>
<xs:element name="fullname" type="xs:string" minOccurs="0"/>
<xs:element name="okay" type="xs:boolean"/>
<xs:element name="sourceVersion" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="action">
<xs:restriction base="xs:string">
<xs:enumeration value="READ"/>
<xs:enumeration value="WRITE"/>
<xs:enumeration value="DELETE"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>

View File

@@ -2,7 +2,6 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.dspace</groupId>
<artifactId>dspace-server-webapp</artifactId>
<packaging>war</packaging>
<name>DSpace Server Webapp</name>
<description>
DSpace Server Webapp (Spring Boot)
@@ -25,23 +24,82 @@
<!-- Default resource delimiter for Spring Boot, so it doesn't clash with Spring ${} placeholders-->
<resource.delimiter>@</resource.delimiter>
<!-- Define our starting class for our Spring Boot Application -->
<start-class>org.dspace.app.rest.Application</start-class>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<attachClasses>true</attachClasses>
<!-- Filter the web.xml (needed for IDE compatibility/debugging) -->
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
</configuration>
<groupId>org.codehaus.mojo</groupId>
<artifactId>properties-maven-plugin</artifactId>
<version>1.1.0</version>
<executions>
<execution>
<phase>prepare-package</phase>
<phase>initialize</phase>
<goals>
<goal>read-project-properties</goal>
</goals>
<configuration>
<files>
<file>${root.basedir}/dspace/config/dspace.cfg</file>
<file>${root.basedir}/dspace/config/local.cfg</file>
</files>
<quiet>true</quiet>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>testEnvironment</id>
<phase>process-resources</phase>
<goals>
<goal>testResources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/test/resources</directory>
</resource>
</resources>
</configuration>
</execution>
<execution>
<id>webappFiltering</id>
<phase>process-resources</phase>
<goals>
<goal>resources</goal>
</goals>
<configuration>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**/*application*.properties</include>
<include>**/*dspace*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<excludes>
<exclude>**/*application*.properties</exclude>
<exclude>**/*dspace*.properties</exclude>
</excludes>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
<resource>
<directory>${basedir}/src/main/resources</directory>
<includes>
<include>**/static/**</include>
<include>**/spring/**</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
@@ -66,11 +124,11 @@
<exclude>**/src/test/resources/**</exclude>
<exclude>**/src/test/data/**</exclude>
<!--Skip license check of third party files included/customized from HAL Browser -->
<exclude>src/main/webapp/index.html</exclude>
<exclude>src/main/webapp/login.html</exclude>
<exclude>src/main/webapp/styles.css</exclude>
<exclude>src/main/webapp/js/hal/**</exclude>
<exclude>src/main/webapp/js/vendor/**</exclude>
<exclude>src/main/resources/static/index.html</exclude>
<exclude>src/main/resources/static/login.html</exclude>
<exclude>src/main/resources/static/styles.css</exclude>
<exclude>src/main/resources/static/js/hal/**</exclude>
<exclude>src/main/resources/static/js/vendor/**</exclude>
</excludes>
</configuration>
</plugin>
@@ -253,12 +311,6 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
<version>${spring-boot.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -288,7 +340,7 @@
<dependency>
<groupId>com.flipkart.zjsonpatch</groupId>
<artifactId>zjsonpatch</artifactId>
<version>0.4.14</version>
<version>0.4.16</version>
</dependency>
<!-- HAL Browser (via WebJars) : https://github.com/mikekelly/hal-browser -->
@@ -308,7 +360,7 @@
<dependency>
<groupId>org.webjars.bowergithub.jquery</groupId>
<artifactId>jquery-dist</artifactId>
<version>3.7.0</version>
<version>3.7.1</version>
</dependency>
<!-- Pull in current version of Toastr (toastrjs.com) via WebJars
Made available at: webjars/toastr/build/toastr.min.js -->
@@ -354,7 +406,7 @@
<dependency>
<groupId>org.webjars.bowergithub.twbs</groupId>
<artifactId>bootstrap</artifactId>
<version>4.6.1</version>
<version>4.6.2</version>
</dependency>
<!-- Add in Spring Security for AuthN and AuthZ -->
@@ -484,12 +536,10 @@
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
@@ -498,7 +548,7 @@
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-all</artifactId>
<artifactId>hamcrest</artifactId>
<scope>test</scope>
</dependency>
<dependency>

View File

@@ -138,6 +138,7 @@ public class BitstreamRestController {
.withBufferSize(BUFFER_SIZE)
.withFileName(name)
.withChecksum(bit.getChecksum())
.withLength(bit.getSizeBytes())
.withMimetype(mimetype)
.with(request)
.with(response);
@@ -167,6 +168,12 @@ public class BitstreamRestController {
//Send the data
if (httpHeadersInitializer.isValid()) {
HttpHeaders httpHeaders = httpHeadersInitializer.initialiseHeaders();
if (RequestMethod.HEAD.name().equals(request.getMethod())) {
log.debug("HEAD request - no response body");
return ResponseEntity.ok().headers(httpHeaders).build();
}
return ResponseEntity.ok().headers(httpHeaders).body(bitstreamResource);
}

View File

@@ -17,8 +17,6 @@ import org.dspace.app.rest.model.hateoas.DSpaceLinkRelationProvider;
import org.dspace.app.rest.parameter.resolver.SearchFilterResolver;
import org.dspace.app.rest.utils.ApplicationConfig;
import org.dspace.app.rest.utils.DSpaceAPIRequestLoggingFilter;
import org.dspace.app.rest.utils.DSpaceConfigurationInitializer;
import org.dspace.app.rest.utils.DSpaceKernelInitializer;
import org.dspace.app.sitemap.GenerateSitemaps;
import org.dspace.app.solrdatabaseresync.SolrDatabaseResyncCli;
import org.dspace.app.util.DSpaceContextListener;
@@ -27,11 +25,9 @@ import org.dspace.utils.servlet.DSpaceWebappServletFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.hateoas.server.LinkRelationProvider;
import org.springframework.lang.NonNull;
@@ -46,24 +42,18 @@ import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* Define the Spring Boot Application settings itself. This class takes the place
* of a web.xml file, and configures all Filters/Listeners as methods (see below).
* <p>
* NOTE: Requires a Servlet 3.0 container, e.g. Tomcat 7.0 or above.
* <p>
* NOTE: This extends SpringBootServletInitializer in order to allow us to build
* a deployable WAR file with Spring Boot. See:
* http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-create-a-deployable-war-file
* Main configuration for the dspace web module.
*
* @author Andrea Bollini (andrea.bollini at 4science.it)
* @author Tim Donohue
* @author Luca Giamminonni (luca.giamminonni at 4science.it)
*/
@SpringBootApplication
@EnableScheduling
@EnableCaching
public class Application extends SpringBootServletInitializer {
@Configuration
public class WebApplication {
private static final Logger log = LoggerFactory.getLogger(Application.class);
private static final Logger log = LoggerFactory.getLogger(WebApplication.class);
@Autowired
private ApplicationConfig configuration;
@@ -86,26 +76,6 @@ public class Application extends SpringBootServletInitializer {
googleAsyncEventListener.sendCollectedEvents();
}
/**
* Override the default SpringBootServletInitializer.configure() method,
* passing it this Application class.
* <p>
* This is necessary to allow us to build a deployable WAR, rather than
* always relying on embedded Tomcat.
* <p>
* See: http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto-create-a-deployable-war-file
*
* @param application
* @return
*/
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
// Pass this Application class, and our initializers for DSpace Kernel and Configuration
// NOTE: Kernel must be initialized before Configuration
return application.sources(Application.class)
.initializers(new DSpaceKernelInitializer(), new DSpaceConfigurationInitializer());
}
/**
* Register the "DSpaceContextListener" so that it is loaded
* for this Application.
@@ -253,7 +223,7 @@ public class Application extends SpringBootServletInitializer {
// Make all other Webjars available off the /webjars path
registry
.addResourceHandler("/webjars/**")
.addResourceLocations("/webjars/");
.addResourceLocations("/webjars/", "classpath:/META-INF/resources/webjars/");
}
@Override

View File

@@ -43,6 +43,7 @@ public class ProcessConverter implements DSpaceConverter<Process, ProcessRest> {
processRest.setProcessStatus(process.getProcessStatus());
processRest.setStartTime(process.getStartTime());
processRest.setEndTime(process.getFinishedTime());
processRest.setCreationTime(process.getCreationTime());
processRest.setParameterRestList(processService.getParameters(process).stream()
.map(x -> (ParameterValueRest) converter.toRest(x, projection)).collect(Collectors.toList()));
return processRest;

View File

@@ -21,6 +21,8 @@ import org.dspace.app.rest.model.RestModel;
import org.dspace.app.rest.model.hateoas.DSpaceResource;
import org.dspace.app.rest.utils.Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.data.domain.Pageable;
import org.springframework.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
@@ -33,6 +35,7 @@ import org.springframework.stereotype.Component;
* @author Tom Desair (tom dot desair at atmire dot com)
*/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DSpaceResourceHalLinkFactory extends HalLinkFactory<DSpaceResource, RestResourceController> {
@Autowired

View File

@@ -60,6 +60,7 @@ public class ProcessRest extends BaseObjectRest<Integer> {
private Integer processId;
private Date startTime;
private Date endTime;
private Date creationTime;
private ProcessStatus processStatus;
@JsonProperty(value = "parameters")
private List<ParameterValueRest> parameterRestList;
@@ -104,6 +105,14 @@ public class ProcessRest extends BaseObjectRest<Integer> {
this.startTime = startTime;
}
public Date getCreationTime() {
return creationTime;
}
public void setCreationTime(Date creationTime) {
this.creationTime = creationTime;
}
public String getScriptName() {
return scriptName;
}

Some files were not shown because too many files have changed in this diff Show More