diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index 11cf2a3a5b..fb6a90d965 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -51,6 +51,10 @@ true true + + org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor + + @@ -308,6 +312,10 @@ org.hibernate hibernate-ehcache + + org.hibernate + hibernate-jpamodelgen + org.hibernate hibernate-validator-cdi diff --git a/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickThumbnailFilter.java b/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickThumbnailFilter.java index 58bae2e22b..27413544b9 100644 --- a/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickThumbnailFilter.java +++ b/dspace-api/src/main/java/org/dspace/app/mediafilter/ImageMagickThumbnailFilter.java @@ -143,7 +143,7 @@ public abstract class ImageMagickThumbnailFilter extends MediaFilter { // PDFs using the CMYK color system can be handled specially if // profiles are defined if (cmyk_profile != null && srgb_profile != null) { - Info imageInfo = new Info(f.getAbsolutePath(), true); + Info imageInfo = new Info(f.getAbsolutePath() + s, true); String imageClass = imageInfo.getImageClass(); if (imageClass.contains("CMYK")) { op.profile(cmyk_profile); diff --git a/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java index 5d9cb1f666..351f40ae13 100644 --- a/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/app/requestitem/dao/impl/RequestItemDAOImpl.java @@ -8,13 +8,15 @@ package org.dspace.app.requestitem.dao.impl; import java.sql.SQLException; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.app.requestitem.RequestItem; +import org.dspace.app.requestitem.RequestItem_; import org.dspace.app.requestitem.dao.RequestItemDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the RequestItem object. @@ -30,9 +32,12 @@ public class RequestItemDAOImpl extends AbstractHibernateDAO implem @Override public RequestItem findByToken(Context context, String token) throws SQLException { - Criteria criteria = createCriteria(context, RequestItem.class); - criteria.add(Restrictions.eq("token", token)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RequestItem.class); + Root requestItemRoot = criteriaQuery.from(RequestItem.class); + criteriaQuery.select(requestItemRoot); + criteriaQuery.where(criteriaBuilder.equal(requestItemRoot.get(RequestItem_.token), token)); + return uniqueResult(context, criteriaQuery, false, RequestItem.class, -1, -1); } diff --git a/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java b/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java index 22095fa0b1..a0f69dc526 100644 --- a/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/authorize/dao/impl/ResourcePolicyDAOImpl.java @@ -9,17 +9,19 @@ package org.dspace.authorize.dao.impl; import java.sql.SQLException; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.authorize.ResourcePolicy; +import org.dspace.authorize.ResourcePolicy_; import org.dspace.authorize.dao.ResourcePolicyDAO; import org.dspace.content.DSpaceObject; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the ResourcePolicy object. @@ -36,79 +38,104 @@ public class ResourcePolicyDAOImpl extends AbstractHibernateDAO @Override public List findByDso(Context context, DSpaceObject dso) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso) - )); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery.where(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso)); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override public List findByDsoAndType(Context context, DSpaceObject dso, String type) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - Restrictions.eq("rptype", type) - )); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.rptype), type) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override public List findByGroup(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.eq("epersonGroup", group)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery.where(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.epersonGroup), group)); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override public List findByDSoAndAction(Context context, DSpaceObject dso, int actionId) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - Restrictions.eq("actionId", actionId) - )); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.actionId), actionId) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, -1, -1); } @Override public List findByTypeGroupAction(Context context, DSpaceObject dso, Group group, int action) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - Restrictions.eq("epersonGroup", group), - Restrictions.eq("actionId", action) - )); - criteria.setMaxResults(1); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso), + criteriaBuilder + .equal(resourcePolicyRoot.get(ResourcePolicy_.epersonGroup), group), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.actionId), action) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, 1, -1); } @Override public List findByTypeGroupActionExceptId(Context context, DSpaceObject dso, Group group, int action, int notPolicyID) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - Restrictions.eq("epersonGroup", group), - Restrictions.eq("actionId", action) - )); - criteria.add(Restrictions.and(Restrictions.not(Restrictions.eq("id", notPolicyID)))); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.dSpaceObject), dso), + criteriaBuilder + .equal(resourcePolicyRoot.get(ResourcePolicy_.epersonGroup), group), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.actionId), action), + criteriaBuilder.notEqual(resourcePolicyRoot.get(ResourcePolicy_.id), notPolicyID) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, 1, -1); } public List findByEPersonGroupTypeIdAction(Context context, EPerson e, List groups, int action, int type_id) throws SQLException { - Criteria criteria = createCriteria(context, ResourcePolicy.class); - criteria.add(Restrictions.and( - Restrictions.eq("resourceTypeId", type_id), - Restrictions.eq("actionId", action), - (Restrictions.or( - Restrictions.eq("eperson", e), - Restrictions.in("epersonGroup", groups) - )) - )); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ResourcePolicy.class); + Root resourcePolicyRoot = criteriaQuery.from(ResourcePolicy.class); + criteriaQuery.select(resourcePolicyRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.resourceTypeId), type_id), + criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.actionId), action), + criteriaBuilder + .or(criteriaBuilder.equal(resourcePolicyRoot.get(ResourcePolicy_.eperson), e), + criteriaBuilder + .in(resourcePolicyRoot.get(ResourcePolicy_.epersonGroup).in(groups))) + ) + ); + return list(context, criteriaQuery, false, ResourcePolicy.class, 1, -1); } @Override @@ -124,7 +151,7 @@ public class ResourcePolicyDAOImpl extends AbstractHibernateDAO String queryString = "delete from ResourcePolicy where dSpaceObject= :dSpaceObject AND actionId= :actionId"; Query query = createQuery(context, queryString); query.setParameter("dSpaceObject", dso); - query.setInteger("actionId", actionId); + query.setParameter("actionId", actionId); query.executeUpdate(); } @@ -133,7 +160,7 @@ public class ResourcePolicyDAOImpl extends AbstractHibernateDAO String queryString = "delete from ResourcePolicy where dSpaceObject.id = :dsoId AND rptype = :rptype"; Query query = createQuery(context, queryString); query.setParameter("dsoId", dso.getID()); - query.setString("rptype", type); + query.setParameter("rptype", type); query.executeUpdate(); } diff --git a/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImpl.java b/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImpl.java index 753bb6267d..328d4a717e 100644 --- a/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImpl.java @@ -9,6 +9,8 @@ package org.dspace.checker.dao.impl; import java.sql.SQLException; import java.util.Date; +import javax.persistence.Query; +import javax.persistence.TemporalType; import org.dspace.checker.ChecksumHistory; import org.dspace.checker.ChecksumResultCode; @@ -16,7 +18,6 @@ import org.dspace.checker.dao.ChecksumHistoryDAO; import org.dspace.content.Bitstream; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Query; /** *

@@ -29,6 +30,8 @@ import org.hibernate.Query; * @author Grace Carpenter * @author Nathan Sarr * @author kevinvandevelde at atmire.com + * + * */ public class ChecksumHistoryDAOImpl extends AbstractHibernateDAO implements ChecksumHistoryDAO { @@ -42,7 +45,7 @@ public class ChecksumHistoryDAOImpl extends AbstractHibernateDAO @Override public ChecksumResult findByCode(Context context, ChecksumResultCode code) throws SQLException { - Criteria criteria = createCriteria(context, ChecksumResult.class); - criteria.add(Restrictions.eq("resultCode", code)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ChecksumResult.class); + Root checksumResultRoot = criteriaQuery.from(ChecksumResult.class); + criteriaQuery.select(checksumResultRoot); + criteriaQuery.where(criteriaBuilder.equal(checksumResultRoot.get(ChecksumResult_.resultCode), code)); + return uniqueResult(context, criteriaQuery, false, ChecksumResult.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/checker/dao/impl/MostRecentChecksumDAOImpl.java b/dspace-api/src/main/java/org/dspace/checker/dao/impl/MostRecentChecksumDAOImpl.java index 9ed89c40e9..66ce666b9d 100644 --- a/dspace-api/src/main/java/org/dspace/checker/dao/impl/MostRecentChecksumDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/checker/dao/impl/MostRecentChecksumDAOImpl.java @@ -9,22 +9,27 @@ package org.dspace.checker.dao.impl; import java.sql.SQLException; import java.util.Date; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Order; +import javax.persistence.criteria.Root; +import javax.persistence.criteria.Subquery; import org.dspace.checker.ChecksumHistory; +import org.dspace.checker.ChecksumHistory_; +import org.dspace.checker.ChecksumResult; import org.dspace.checker.ChecksumResultCode; +import org.dspace.checker.ChecksumResult_; import org.dspace.checker.MostRecentChecksum; +import org.dspace.checker.MostRecentChecksum_; import org.dspace.checker.dao.MostRecentChecksumDAO; import org.dspace.content.Bitstream; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.Query; -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; /** * Hibernate implementation of the Database Access Object interface class for the MostRecentChecksum object. @@ -43,58 +48,58 @@ public class MostRecentChecksumDAOImpl extends AbstractHibernateDAO findByNotProcessedInDateRange(Context context, Date startDate, Date endDate) throws SQLException { -// + "most_recent_checksum.last_process_start_date, most_recent_checksum.last_process_end_date, " -// + "most_recent_checksum.expected_checksum, most_recent_checksum.current_checksum, " -// + "result_description " -// + "from checksum_results, most_recent_checksum " -// + "where most_recent_checksum.to_be_processed = false " -// + "and most_recent_checksum.result = checksum_results.result_code " -// + "and most_recent_checksum.last_process_start_date >= ? " -// + "and most_recent_checksum.last_process_start_date < ? " -// + "order by most_recent_checksum.bitstream_id - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - criteria.add( - Restrictions.and( - Restrictions.eq("toBeProcessed", false), - Restrictions.le("processStartDate", startDate), - Restrictions.gt("processStartDate", endDate) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(mostRecentChecksumRoot.get(MostRecentChecksum_.toBeProcessed), false), + criteriaBuilder + .lessThanOrEqualTo(mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), startDate), + criteriaBuilder.greaterThan(mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), endDate) + ) ); - criteria.addOrder(Order.asc("bitstream.id")); - return list(criteria); + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream))); + criteriaQuery.orderBy(orderList); + return list(context, criteriaQuery, false, MostRecentChecksum.class, -1, -1); } @Override public MostRecentChecksum findByBitstream(Context context, Bitstream bitstream) throws SQLException { - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - criteria.add(Restrictions.eq("bitstream", bitstream)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery + .where(criteriaBuilder.equal(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream), bitstream)); + return singleResult(context, criteriaQuery); } @Override public List findByResultTypeInDateRange(Context context, Date startDate, Date endDate, ChecksumResultCode resultCode) throws SQLException { -// "select bitstream_id, last_process_start_date, last_process_end_date, " -// + "expected_checksum, current_checksum, result_description " -// + "from most_recent_checksum, checksum_results " -// + "where most_recent_checksum.result = checksum_results.result_code " -// + "and most_recent_checksum.result= ? " -// + "and most_recent_checksum.last_process_start_date >= ? " -// + "and most_recent_checksum.last_process_start_date < ? " -// + "order by bitstream_id"; - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - criteria.add( - Restrictions.and( - Restrictions.eq("checksumResult.resultCode", resultCode), - Restrictions.le("processStartDate", startDate), - Restrictions.gt("processStartDate", endDate) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + Join mostRecentResult = + mostRecentChecksumRoot.join(MostRecentChecksum_.checksumResult); + + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(mostRecentResult.get(ChecksumResult_.resultCode), resultCode), + criteriaBuilder.lessThanOrEqualTo( + mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), startDate), + criteriaBuilder.greaterThan(mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), endDate) + ) ); - criteria.addOrder(Order.asc("bitstream.id")); - return list(criteria); + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream))); + criteriaQuery.orderBy(orderList); + return list(context, criteriaQuery, false, MostRecentChecksum.class, -1, -1); } @@ -108,42 +113,52 @@ public class MostRecentChecksumDAOImpl extends AbstractHibernateDAO criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery.where(criteriaBuilder.equal(mostRecentChecksumRoot.get(MostRecentChecksum_.toBeProcessed), true)); + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.processEndDate))); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream))); + criteriaQuery.orderBy(orderList); + return singleResult(context, criteriaQuery); } @Override public MostRecentChecksum getOldestRecord(Context context, Date lessThanDate) throws SQLException { -// "select bitstream_id " -// + "from most_recent_checksum " -// + "where to_be_processed = true " -// + "and last_process_start_date < ? " -// + "order by date_trunc('milliseconds', last_process_end_date), " -// + "bitstream_id " + "ASC LIMIT 1"; - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - criteria.add( - Restrictions.and( - Restrictions.eq("toBeProcessed", true), - Restrictions.lt("processStartDate", lessThanDate) - )); - criteria.addOrder(Order.asc("processEndDate")).addOrder(Order.asc("bitstream.id")); - criteria.setMaxResults(1); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root mostRecentChecksumRoot = criteriaQuery.from(MostRecentChecksum.class); + criteriaQuery.select(mostRecentChecksumRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(mostRecentChecksumRoot.get(MostRecentChecksum_.toBeProcessed), true), + criteriaBuilder.lessThan(mostRecentChecksumRoot.get(MostRecentChecksum_.processStartDate), lessThanDate) + ) + ); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.processEndDate))); + orderList.add(criteriaBuilder.asc(mostRecentChecksumRoot.get(MostRecentChecksum_.bitstream))); + criteriaQuery.orderBy(orderList); + + return singleResult(context, criteriaQuery); } @Override public List findNotInHistory(Context context) throws SQLException { - Criteria criteria = createCriteria(context, MostRecentChecksum.class); - DetachedCriteria subCriteria = DetachedCriteria.forClass(ChecksumHistory.class); - subCriteria.setProjection(Projections.property("bitstream.id")); - criteria.add(Property.forName("bitstreamId").notIn(subCriteria)); - return list(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MostRecentChecksum.class); + Root checksumRoot = criteriaQuery.from(MostRecentChecksum.class); + + Subquery subQuery = criteriaQuery.subquery(Bitstream.class); + Root historyRoot = subQuery.from(ChecksumHistory.class); + subQuery.select(historyRoot.get(ChecksumHistory_.bitstream)); + + criteriaQuery.where( + criteriaBuilder.not(checksumRoot.get(MostRecentChecksum_.bitstream).in(subQuery))); + + return list(context, criteriaQuery, false, MostRecentChecksum.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamDAOImpl.java index fff7c42206..02e3509c31 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamDAOImpl.java @@ -8,10 +8,17 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.Bitstream; +import org.dspace.content.Bitstream_; import org.dspace.content.Collection; import org.dspace.content.Community; import org.dspace.content.Item; @@ -19,9 +26,6 @@ import org.dspace.content.dao.BitstreamDAO; import org.dspace.core.AbstractHibernateDSODAO; import org.dspace.core.Constants; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the Bitstream object. @@ -38,40 +42,35 @@ public class BitstreamDAOImpl extends AbstractHibernateDSODAO impleme @Override public List findDeletedBitstreams(Context context) throws SQLException { - Criteria criteria = createCriteria(context, Bitstream.class); - criteria.add(Restrictions.eq("deleted", true)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Bitstream.class); + Root bitstreamRoot = criteriaQuery.from(Bitstream.class); + criteriaQuery.select(bitstreamRoot); + criteriaQuery.where(criteriaBuilder.equal(bitstreamRoot.get(Bitstream_.deleted), true)); + return list(context, criteriaQuery, false, Bitstream.class, -1, -1); } @Override public List findDuplicateInternalIdentifier(Context context, Bitstream bitstream) throws SQLException { - Criteria criteria = createCriteria(context, Bitstream.class); - criteria.add(Restrictions.and( - Restrictions.eq("internalId", bitstream.getInternalId()), - Restrictions.not(Restrictions.eq("id", bitstream.getID())) - )); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Bitstream.class); + Root bitstreamRoot = criteriaQuery.from(Bitstream.class); + criteriaQuery.select(bitstreamRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(bitstreamRoot.get(Bitstream_.internalId), bitstream.getInternalId()), + criteriaBuilder.notEqual(bitstreamRoot.get(Bitstream_.id), bitstream.getID()) + ) + ); + return list(context, criteriaQuery, false, Bitstream.class, -1, -1); } @Override public List findBitstreamsWithNoRecentChecksum(Context context) throws SQLException { -// "select bitstream.deleted, bitstream.store_number, bitstream.size_bytes, " -// + "bitstreamformatregistry.short_description, bitstream.bitstream_id, " -// + "bitstream.user_format_description, bitstream.internal_id, " -// + "bitstream.source, bitstream.checksum_algorithm, bitstream.checksum, " -// + "bitstream.name, bitstream.description " -// + "from bitstream left outer join bitstreamformatregistry on " -// + "bitstream.bitstream_format_id = bitstreamformatregistry.bitstream_format_id " -// + "where not exists( select 'x' from most_recent_checksum " -// + "where most_recent_checksum.bitstream_id = bitstream.bitstream_id )" - Query query = createQuery(context, "select b from Bitstream b where b not in (select c.bitstream from " + "MostRecentChecksum c)"); - return query.list(); + return query.getResultList(); } @Override @@ -122,9 +121,14 @@ public class BitstreamDAOImpl extends AbstractHibernateDSODAO impleme @Override public Long countByStoreNumber(Context context, Integer storeNumber) throws SQLException { - Criteria criteria = createCriteria(context, Bitstream.class); - criteria.add(Restrictions.eq("storeNumber", storeNumber)); - return countLong(criteria); + + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root bitstreamRoot = criteriaQuery.from(Bitstream.class); + criteriaQuery.where(criteriaBuilder.equal(bitstreamRoot.get(Bitstream_.storeNumber), storeNumber)); + return countLong(context, criteriaQuery, criteriaBuilder, bitstreamRoot); } @Override @@ -158,9 +162,8 @@ public class BitstreamDAOImpl extends AbstractHibernateDSODAO impleme @Override public Iterator findAll(Context context, int limit, int offset) throws SQLException { - Query query = createQuery(context, "select b FROM Bitstream b"); - query.setFirstResult(offset); - query.setMaxResults(limit); - return iterate(query); + Map map = new HashMap<>(); + return findByX(context, Bitstream.class, map, true, limit, offset).iterator(); + } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamFormatDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamFormatDAOImpl.java index 51b0af51de..0824c5c343 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamFormatDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/BitstreamFormatDAOImpl.java @@ -8,16 +8,18 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.BitstreamFormat; +import org.dspace.content.BitstreamFormat_; import org.dspace.content.dao.BitstreamFormatDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the BitstreamFormat object. @@ -37,11 +39,14 @@ public class BitstreamFormatDAOImpl extends AbstractHibernateDAOnull if - * there's no bitstream format with the given MIMEtype. + * there's no bitstream format with the given MIMEtype. * @throws SQLException if database error */ @Override @@ -49,33 +54,39 @@ public class BitstreamFormatDAOImpl extends AbstractHibernateDAO bitstreamFormatRoot = criteriaQuery.from(BitstreamFormat.class); + criteriaQuery.select(bitstreamFormatRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(bitstreamFormatRoot.get(BitstreamFormat_.internal), includeInternal), + criteriaBuilder.like(bitstreamFormatRoot.get(BitstreamFormat_.mimetype), mimeType) + ) + ); + return singleResult(context, criteriaQuery); } /** * Find a bitstream format by its (unique) short description * - * @param context DSpace context object - * @param desc the short description + * @param context + * DSpace context object + * @param desc + * the short description + * * @return the corresponding bitstream format, or null if - * there's no bitstream format with the given short description + * there's no bitstream format with the given short description * @throws SQLException if database error */ @Override public BitstreamFormat findByShortDescription(Context context, String desc) throws SQLException { - Criteria criteria = createCriteria(context, BitstreamFormat.class); - criteria.add(Restrictions.and( - Restrictions.eq("shortDescription", desc) - )); - - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BitstreamFormat.class); + Root bitstreamFormatRoot = criteriaQuery.from(BitstreamFormat.class); + criteriaQuery.select(bitstreamFormatRoot); + criteriaQuery.where(criteriaBuilder.equal(bitstreamFormatRoot.get(BitstreamFormat_.shortDescription), desc)); + return uniqueResult(context, criteriaQuery, false, BitstreamFormat.class, -1, -1); } @Override @@ -93,14 +104,28 @@ public class BitstreamFormatDAOImpl extends AbstractHibernateDAO findNonInternal(Context context) throws SQLException { - Criteria criteria = createCriteria(context, BitstreamFormat.class); - criteria.add(Restrictions.and( - Restrictions.eq("internal", false), - Restrictions.not(Restrictions.like("shortDescription", "Unknown")) - )); - criteria.addOrder(Order.desc("supportLevel")).addOrder(Order.asc("shortDescription")); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BitstreamFormat.class); + Root bitstreamFormatRoot = criteriaQuery.from(BitstreamFormat.class); + criteriaQuery.select(bitstreamFormatRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(bitstreamFormatRoot.get(BitstreamFormat_.internal), false), + criteriaBuilder.not( + criteriaBuilder + .like(bitstreamFormatRoot.get(BitstreamFormat_.shortDescription), + "Unknown")) + ) + ); + + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.desc(bitstreamFormatRoot.get(BitstreamFormat_.supportLevel))); + orderList.add(criteriaBuilder.asc(bitstreamFormatRoot.get(BitstreamFormat_.shortDescription))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, BitstreamFormat.class, -1, -1); } @@ -110,17 +135,22 @@ public class BitstreamFormatDAOImpl extends AbstractHibernateDAO findAll(Context context, Class clazz) throws SQLException { - Criteria criteria = createCriteria(context, BitstreamFormat.class); - criteria.addOrder(Order.asc("id")); - return list(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BitstreamFormat.class); + Root bitstreamFormatRoot = criteriaQuery.from(BitstreamFormat.class); + criteriaQuery.select(bitstreamFormatRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(bitstreamFormatRoot.get(BitstreamFormat_.id))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, false, BitstreamFormat.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java index 14b1587315..9180fb3c09 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/CollectionDAOImpl.java @@ -8,11 +8,22 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; +import java.util.AbstractMap; import java.util.Arrays; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import org.dspace.authorize.ResourcePolicy; +import org.dspace.authorize.ResourcePolicy_; import org.dspace.content.Collection; +import org.dspace.content.Collection_; import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.dao.CollectionDAO; @@ -21,11 +32,6 @@ import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.Restrictions; -import org.hibernate.transform.BasicTransformerAdapter; /** * Hibernate implementation of the Database Access Object interface class for the Collection object. @@ -43,8 +49,9 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO imple * Get all collections in the system. These are alphabetically sorted by * collection name. * - * @param context DSpace context object - * @param order order by MetadataField + * @param context + * DSpace context object + * @param order order by MetadataField * @return the collections in the system * @throws SQLException if database error */ @@ -75,77 +82,54 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO imple @Override public Collection findByTemplateItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, Collection.class); - criteria.add(Restrictions.eq("template_item", item)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Collection.class); + Root collectionRoot = criteriaQuery.from(Collection.class); + criteriaQuery.select(collectionRoot); + criteriaQuery.where(criteriaBuilder.equal(collectionRoot.get(Collection_.template), item)); + return uniqueResult(context, criteriaQuery, false, Collection.class, -1, -1); } @Override public Collection findByGroup(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, Collection.class); - criteria.add( - Restrictions.or( - Restrictions.eq("workflowStep1", group), - Restrictions.eq("workflowStep2", group), - Restrictions.eq("workflowStep3", group), - Restrictions.eq("submitters", group), - Restrictions.eq("admins", group) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Collection.class); + Root collectionRoot = criteriaQuery.from(Collection.class); + criteriaQuery.select(collectionRoot); + criteriaQuery + .where(criteriaBuilder.or(criteriaBuilder.equal(collectionRoot.get(Collection_.workflowStep1), group), + criteriaBuilder.equal(collectionRoot.get(Collection_.workflowStep2), group), + criteriaBuilder.equal(collectionRoot.get(Collection_.workflowStep3), group), + criteriaBuilder.equal(collectionRoot.get(Collection_.submitters), group), + criteriaBuilder.equal(collectionRoot.get(Collection_.admins), group) + ) ); - return singleResult(criteria); + return singleResult(context, criteriaQuery); } @Override public List findAuthorized(Context context, EPerson ePerson, List actions) throws SQLException { - // TableRowIterator tri = DatabaseManager.query(context, -// "SELECT * FROM collection, resourcepolicy, eperson " + -// "WHERE resourcepolicy.resource_id = collection.collection_id AND " + -// "eperson.eperson_id = resourcepolicy.eperson_id AND "+ -// "resourcepolicy.resource_type_id = 3 AND "+ -// "( resourcepolicy.action_id = 3 OR resourcepolicy.action_id = 11 ) AND "+ -// "eperson.eperson_id = ?", context.getCurrentUser().getID()); - - Criteria criteria = createCriteria(context, Collection.class); - criteria.createAlias("resourcePolicies", "resourcePolicy"); - - Disjunction actionQuery = Restrictions.or(); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Collection.class); + Root collectionRoot = criteriaQuery.from(Collection.class); + Join join = collectionRoot.join("resourcePolicies"); + List orPredicates = new LinkedList(); for (Integer action : actions) { - actionQuery.add(Restrictions.eq("resourcePolicy.actionId", action)); + orPredicates.add(criteriaBuilder.equal(join.get(ResourcePolicy_.actionId), action)); } - criteria.add(Restrictions.and( - Restrictions.eq("resourcePolicy.resourceTypeId", Constants.COLLECTION), - Restrictions.eq("resourcePolicy.eperson", ePerson), - actionQuery - )); - criteria.setCacheable(true); - - return list(criteria); + Predicate orPredicate = criteriaBuilder.or(orPredicates.toArray(new Predicate[] {})); + criteriaQuery.select(collectionRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(join.get(ResourcePolicy_.resourceTypeId), Constants.COLLECTION), + criteriaBuilder.equal(join.get(ResourcePolicy_.eperson), ePerson), + orPredicate)); + return list(context, criteriaQuery, true, Collection.class, -1, -1); } @Override public List findAuthorizedByGroup(Context context, EPerson ePerson, List actions) throws SQLException { - // TableRowIterator tri = DatabaseManager.query(context, - // "SELECT \n" + - // " * \n" + - // "FROM \n" + - // " public.eperson, \n" + - // " public.epersongroup2eperson, \n" + - // " public.epersongroup, \n" + - // " public.group2group, \n" + - // " public.resourcepolicy rp_parent, \n" + - // " public.collection\n" + - // "WHERE \n" + - // " epersongroup2eperson.eperson_id = eperson.eperson_id AND\n" + - // " epersongroup.eperson_group_id = epersongroup2eperson.eperson_group_id AND\n" + - // " group2group.child_id = epersongroup.eperson_group_id AND\n" + - // " rp_parent.epersongroup_id = group2group.parent_id AND\n" + - // " collection.collection_id = rp_parent.resource_id AND\n" + - // " eperson.eperson_id = ? AND \n" + - // " (rp_parent.action_id = 3 OR \n" + - // " rp_parent.action_id = 11 \n" + - // " ) AND rp_parent.resource_type_id = 3;", context.getCurrentUser().getID()); StringBuilder query = new StringBuilder(); query.append("select c from Collection c join c.resourcePolicies rp join rp.epersonGroup rpGroup WHERE "); for (int i = 0; i < actions.size(); i++) { @@ -159,11 +143,11 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO imple query.append( " AND rp.epersonGroup.id IN (select g.id from Group g where (from EPerson e where e.id = :eperson_id) in " + "elements(epeople))"); - Query hibernateQuery = createQuery(context, query.toString()); - hibernateQuery.setParameter("eperson_id", ePerson.getID()); - hibernateQuery.setCacheable(true); + Query persistenceQuery = createQuery(context, query.toString()); + persistenceQuery.setParameter("eperson_id", ePerson.getID()); + persistenceQuery.setHint("org.hibernate.cacheable", Boolean.TRUE); - return list(hibernateQuery); + return list(persistenceQuery); } @@ -185,12 +169,12 @@ public class CollectionDAOImpl extends AbstractHibernateDSODAO imple String q = "select col as collection, sum(bit.sizeBytes) as totalBytes from Item i join i.collections col " + "join i.bundles bun join bun.bitstreams bit group by col"; Query query = createQuery(context, q); - query.setResultTransformer(new BasicTransformerAdapter() { - @Override - public Object transformTuple(Object[] tuple, String[] aliases) { - return new java.util.AbstractMap.SimpleImmutableEntry<>((Collection) tuple[0], (Long) tuple[1]); - } - }); - return ((List>) query.list()); + + List list = query.getResultList(); + List> returnList = new LinkedList<>(); + for (Object[] o : list) { + returnList.add(new AbstractMap.SimpleEntry<>((Collection) o[0], (Long) o[1])); + } + return returnList; } -} +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/CommunityDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/CommunityDAOImpl.java index 36d2888e01..67bbd18d91 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/CommunityDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/CommunityDAOImpl.java @@ -10,9 +10,19 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; import java.util.Arrays; import java.util.Collections; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import org.dspace.authorize.ResourcePolicy; +import org.dspace.authorize.ResourcePolicy_; import org.dspace.content.Community; +import org.dspace.content.Community_; import org.dspace.content.MetadataField; import org.dspace.content.dao.CommunityDAO; import org.dspace.core.AbstractHibernateDSODAO; @@ -20,10 +30,6 @@ import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the Community object. @@ -41,8 +47,9 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO impleme * Get a list of all communities in the system. These are alphabetically * sorted by community name. * - * @param context DSpace context object + * @param context DSpace context object * @param sortField sort field + * * @return the communities in the system * @throws SQLException if database error */ @@ -73,9 +80,12 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO impleme @Override public Community findByAdminGroup(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, Community.class); - criteria.add(Restrictions.eq("admins", group)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Community.class); + Root communityRoot = criteriaQuery.from(Community.class); + criteriaQuery.select(communityRoot); + criteriaQuery.where(criteriaBuilder.equal(communityRoot.get(Community_.admins), group)); + return singleResult(context, criteriaQuery); } @Override @@ -88,7 +98,8 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO impleme Query query = createQuery(context, queryBuilder.toString()); query.setParameter(sortField.toString(), sortField.getID()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); + return findMany(context, query); } @@ -115,42 +126,29 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO impleme " resourcepolicy.resource_type_id = 4 AND eperson.eperson_id = ?", context.getCurrentUser() .getID()); */ - Criteria criteria = createCriteria(context, Community.class); - criteria.createAlias("resourcePolicies", "resourcePolicy"); - Disjunction actionQuery = Restrictions.or(); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Community.class); + Root communityRoot = criteriaQuery.from(Community.class); + Join join = communityRoot.join("resourcePolicies"); + List orPredicates = new LinkedList(); for (Integer action : actions) { - actionQuery.add(Restrictions.eq("resourcePolicy.actionId", action)); + orPredicates.add(criteriaBuilder.equal(join.get(ResourcePolicy_.actionId), action)); } - criteria.add(Restrictions.and( - Restrictions.eq("resourcePolicy.resourceTypeId", Constants.COMMUNITY), - Restrictions.eq("resourcePolicy.eperson", ePerson), - actionQuery - )); - criteria.setCacheable(true); - - return list(criteria); + Predicate orPredicate = criteriaBuilder.or(orPredicates.toArray(new Predicate[] {})); + criteriaQuery.select(communityRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(join.get(ResourcePolicy_.resourceTypeId), Constants.COMMUNITY), + criteriaBuilder.equal(join.get(ResourcePolicy_.eperson), ePerson), + orPredicate + ) + ); + return list(context, criteriaQuery, true, Community.class, -1, -1); } @Override public List findAuthorizedByGroup(Context context, EPerson ePerson, List actions) throws SQLException { -// "SELECT \n" + -// " * \n" + -// "FROM \n" + -// " public.eperson, \n" + -// " public.epersongroup2eperson, \n" + -// " public.epersongroup, \n" + -// " public.community, \n" + -// " public.resourcepolicy\n" + -// "WHERE \n" + -// " epersongroup2eperson.eperson_id = eperson.eperson_id AND\n" + -// " epersongroup.eperson_group_id = epersongroup2eperson.eperson_group_id AND\n" + -// " resourcepolicy.epersongroup_id = epersongroup.eperson_group_id AND\n" + -// " resourcepolicy.resource_id = community.community_id AND\n" + -// " ( resourcepolicy.action_id = 3 OR \n" + -// " resourcepolicy.action_id = 11) AND \n" + -// " resourcepolicy.resource_type_id = 4 AND eperson.eperson_id = ?", context.getCurrentUser().getID()); StringBuilder query = new StringBuilder(); query.append("select c from Community c join c.resourcePolicies rp join rp.epersonGroup rpGroup WHERE "); for (int i = 0; i < actions.size(); i++) { @@ -164,11 +162,12 @@ public class CommunityDAOImpl extends AbstractHibernateDSODAO impleme query.append( " AND rp.epersonGroup.id IN (select g.id from Group g where (from EPerson e where e.id = :eperson_id) in " + "elements(epeople))"); - Query hibernateQuery = createQuery(context, query.toString()); - hibernateQuery.setParameter("eperson_id", ePerson.getID()); - hibernateQuery.setCacheable(true); + Query persistenceQuery = createQuery(context, query.toString()); + persistenceQuery.setParameter("eperson_id", ePerson.getID()); - return list(hibernateQuery); + persistenceQuery.setHint("org.hibernate.cacheable", Boolean.TRUE); + + return list(persistenceQuery); } @Override diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java index 4127454b27..67644ee7b4 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/ItemDAOImpl.java @@ -13,6 +13,8 @@ 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 org.apache.log4j.Logger; import org.dspace.content.Collection; @@ -24,7 +26,7 @@ import org.dspace.core.AbstractHibernateDSODAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.hibernate.Criteria; -import org.hibernate.Query; +import org.hibernate.criterion.Criterion; import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Property; @@ -89,7 +91,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA query.setParameter("withdrawn", withdrawn); query.setParameter("discoverable", discoverable); if (lastModified != null) { - query.setTimestamp("last_modified", lastModified); + query.setParameter("last_modified", lastModified, TemporalType.TIMESTAMP); } return iterate(query); } @@ -139,14 +141,68 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA return iterate(query); } - enum OP { equals, not_equals, like, not_like, contains, doesnt_contain, exists, doesnt_exist, matches, - doesnt_match } + 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 findByMetadataQuery(Context context, List> listFieldList, List query_op, List query_val, List collectionUuids, String regexClause, int offset, int limit) throws SQLException { - Criteria criteria = createCriteria(context, Item.class, "item"); + + Criteria criteria = getHibernateSession(context).createCriteria(Item.class, "item"); criteria.setFirstResult(offset); criteria.setMaxResults(limit); @@ -183,20 +239,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA subcriteria.add(Restrictions.in("metadataField", listFieldList.get(i))); } - sb.append(op.name() + " "); - if (op == OP.equals || op == OP.not_equals) { - subcriteria.add(Property.forName("mv.value").eq(query_val.get(i))); - sb.append(query_val.get(i)); - } else if (op == OP.like || op == OP.not_like) { - subcriteria.add(Property.forName("mv.value").like(query_val.get(i))); - sb.append(query_val.get(i)); - } else if (op == OP.contains || op == OP.doesnt_contain) { - subcriteria.add(Property.forName("mv.value").like("%" + query_val.get(i) + "%")); - sb.append(query_val.get(i)); - } else if (op == OP.matches || op == OP.doesnt_match) { - subcriteria.add(Restrictions.sqlRestriction(regexClause, query_val.get(i), StandardBasicTypes.STRING)); - sb.append(query_val.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)); @@ -206,7 +249,8 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA } log.debug(String.format("Running custom query with %d filters", index)); - return list(criteria).iterator(); + return ((List) criteria.list()).iterator(); + } @Override @@ -285,7 +329,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA Query query = createQuery(context, "select count(distinct i) from Item i " + "join i.collections collection " + "WHERE collection IN (:collections) AND i.inArchive=:in_archive AND i.withdrawn=:withdrawn"); - query.setParameterList("collections", collections); + query.setParameter("collections", collections); query.setParameter("in_archive", includeArchived); query.setParameter("withdrawn", includeWithdrawn); @@ -296,7 +340,7 @@ public class ItemDAOImpl extends AbstractHibernateDSODAO implements ItemDA public Iterator findByLastModifiedSince(Context context, Date since) throws SQLException { Query query = createQuery(context, "SELECT i FROM item i WHERE last_modified > :last_modified"); - query.setTimestamp("last_modified", since); + query.setParameter("last_modified", since, TemporalType.TIMESTAMP); return iterate(query); } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataFieldDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataFieldDAOImpl.java index c7e22f3427..de517765ba 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataFieldDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataFieldDAOImpl.java @@ -8,18 +8,22 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; import org.apache.commons.lang.StringUtils; import org.dspace.content.MetadataField; +import org.dspace.content.MetadataField_; import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchema_; import org.dspace.content.dao.MetadataFieldDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.FetchMode; -import org.hibernate.Query; -import org.hibernate.criterion.Order; /** * Hibernate implementation of the Database Access Object interface class for the MetadataField object. @@ -61,8 +65,8 @@ public class MetadataFieldDAOImpl extends AbstractHibernateDAO im if (qualifier != null) { query.setParameter("qualifier", qualifier); } + query.setHint("org.hibernate.cacheable", Boolean.TRUE); - query.setCacheable(true); return singleResult(query); } @@ -97,19 +101,27 @@ public class MetadataFieldDAOImpl extends AbstractHibernateDAO im if (StringUtils.isNotBlank(qualifier)) { query.setParameter("qualifier", qualifier); } + query.setHint("org.hibernate.cacheable", Boolean.TRUE); - query.setCacheable(true); return singleResult(query); } @Override public List findAll(Context context, Class clazz) throws SQLException { - Criteria criteria = createCriteria(context, MetadataField.class); - criteria.createAlias("metadataSchema", "s").addOrder(Order.asc("s.name")).addOrder(Order.asc("element")) - .addOrder(Order.asc("qualifier")); - criteria.setFetchMode("metadataSchema", FetchMode.JOIN); - criteria.setCacheable(true); - return list(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MetadataField.class); + Root metadataFieldRoot = criteriaQuery.from(MetadataField.class); + Join join = metadataFieldRoot.join("metadataSchema"); + criteriaQuery.select(metadataFieldRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(join.get(MetadataSchema_.name))); + orderList.add(criteriaBuilder.asc(metadataFieldRoot.get(MetadataField_.element))); + orderList.add(criteriaBuilder.asc(metadataFieldRoot.get(MetadataField_.qualifier))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, true, MetadataField.class, -1, -1, false); } @Override @@ -123,8 +135,8 @@ public class MetadataFieldDAOImpl extends AbstractHibernateDAO im query.setParameter("name", metadataSchema); query.setParameter("element", element); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); - query.setCacheable(true); return list(query); } @@ -140,7 +152,8 @@ public class MetadataFieldDAOImpl extends AbstractHibernateDAO im query.setParameter("name", metadataSchema.getName()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); + return list(query); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataSchemaDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataSchemaDAOImpl.java index 63d37ac195..80198a1e89 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataSchemaDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataSchemaDAOImpl.java @@ -8,15 +8,18 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.MetadataSchema; +import org.dspace.content.MetadataSchema_; import org.dspace.content.dao.MetadataSchemaDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; /** * Hibernate implementation of the Database Access Object interface class for the MetadataSchema object. @@ -33,7 +36,7 @@ public class MetadataSchemaDAOImpl extends AbstractHibernateDAO /** * Get the schema object corresponding to this namespace URI. * - * @param context DSpace context + * @param context DSpace context * @param namespace namespace URI to match * @return metadata schema object or null if none found. * @throws SQLException if database error @@ -46,28 +49,34 @@ public class MetadataSchemaDAOImpl extends AbstractHibernateDAO "WHERE ms.namespace = :namespace "); query.setParameter("namespace", namespace); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); - query.setCacheable(true); return singleResult(query); } @Override public List findAll(Context context, Class clazz) throws SQLException { // Get all the metadataschema rows - Criteria criteria = createCriteria(context, MetadataSchema.class); - criteria.addOrder(Order.asc("id")); - criteria.setCacheable(true); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MetadataSchema.class); + Root metadataSchemaRoot = criteriaQuery.from(MetadataSchema.class); + criteriaQuery.select(metadataSchemaRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(metadataSchemaRoot.get(MetadataSchema_.id))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, true, MetadataSchema.class, -1, -1); } /** * Return true if and only if the passed name appears within the allowed * number of times in the current schema. * - * @param context DSpace context + * @param context DSpace context * @param metadataSchemaId schema id - * @param namespace namespace URI to match + * @param namespace namespace URI to match * @return true of false * @throws SQLException if database error */ @@ -80,16 +89,16 @@ public class MetadataSchemaDAOImpl extends AbstractHibernateDAO query.setParameter("namespace", namespace); query.setParameter("id", metadataSchemaId); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query) == null; } /** * Return true if and only if the passed name is unique. * - * @param context DSpace context + * @param context DSpace context * @param metadataSchemaId schema id - * @param name short name of schema + * @param name short name of schema * @return true of false * @throws SQLException if database error */ @@ -102,15 +111,17 @@ public class MetadataSchemaDAOImpl extends AbstractHibernateDAO query.setParameter("name", name); query.setParameter("id", metadataSchemaId); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query) == null; } /** * Get the schema corresponding with this short name. * - * @param context context, in case we need to read it in from DB - * @param shortName the short name for the schema + * @param context + * context, in case we need to read it in from DB + * @param shortName + * the short name for the schema * @return the metadata schema object * @throws SQLException if database error */ @@ -122,7 +133,7 @@ public class MetadataSchemaDAOImpl extends AbstractHibernateDAO query.setParameter("name", shortName); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java index d800126bdd..a4fdf57cba 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/MetadataValueDAOImpl.java @@ -10,16 +10,18 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; import java.util.Iterator; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; import org.dspace.content.MetadataField; +import org.dspace.content.MetadataField_; import org.dspace.content.MetadataValue; import org.dspace.content.dao.MetadataValueDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; -import org.hibernate.FetchMode; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the MetadataValue object. @@ -36,13 +38,15 @@ public class MetadataValueDAOImpl extends AbstractHibernateDAO im @Override public List findByField(Context context, MetadataField metadataField) throws SQLException { - Criteria criteria = createCriteria(context, MetadataValue.class); - criteria.add( - Restrictions.eq("metadataField.id", metadataField.getID()) - ); - criteria.setFetchMode("metadataField", FetchMode.JOIN); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, MetadataValue.class); + Root metadataValueRoot = criteriaQuery.from(MetadataValue.class); + Join join = metadataValueRoot.join("metadataField"); + criteriaQuery.select(metadataValueRoot); + criteriaQuery.where(criteriaBuilder.equal(join.get(MetadataField_.id), metadataField.getID())); - return list(criteria); + + return list(context, criteriaQuery, false, MetadataValue.class, -1, -1); } @Override @@ -51,7 +55,7 @@ public class MetadataValueDAOImpl extends AbstractHibernateDAO im "WHERE m.value like concat('%', concat(:searchString,'%')) ORDER BY m.id ASC"; Query query = createQuery(context, queryString); - query.setString("searchString", value); + query.setParameter("searchString", value); return iterate(query); } @@ -72,7 +76,7 @@ public class MetadataValueDAOImpl extends AbstractHibernateDAO im Query query = createQuery(context, queryString); query.setParameter("metadata_field_id", metadataFieldId); query.setMaxResults(1); - return (MetadataValue) query.uniqueResult(); + return (MetadataValue) query.getSingleResult(); } @Override diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/SiteDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/SiteDAOImpl.java index 41f7312e5c..4533eab76a 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/SiteDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/SiteDAOImpl.java @@ -8,12 +8,14 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.Site; import org.dspace.content.dao.SiteDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; -import org.hibernate.Criteria; /** * Hibernate implementation of the Database Access Object interface class for the Site object. @@ -29,8 +31,10 @@ public class SiteDAOImpl extends AbstractHibernateDAO implements SiteDAO { @Override public Site findSite(Context context) throws SQLException { - Criteria criteria = createCriteria(context, Site.class); - criteria.setCacheable(true); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Site.class); + Root siteRoot = criteriaQuery.from(Site.class); + criteriaQuery.select(siteRoot); + return uniqueResult(context, criteriaQuery, true, Site.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/content/dao/impl/WorkspaceItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/content/dao/impl/WorkspaceItemDAOImpl.java index ee98889294..8e5e803898 100644 --- a/dspace-api/src/main/java/org/dspace/content/dao/impl/WorkspaceItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/content/dao/impl/WorkspaceItemDAOImpl.java @@ -8,21 +8,26 @@ package org.dspace.content.dao.impl; import java.sql.SQLException; +import java.util.AbstractMap; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; import org.dspace.content.Collection; import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; +import org.dspace.content.WorkspaceItem_; import org.dspace.content.dao.WorkspaceItemDAO; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; -import org.hibernate.transform.BasicTransformerAdapter; +import org.dspace.eperson.EPerson_; +import org.dspace.eperson.Group; /** * Hibernate implementation of the Database Access Object interface class for the WorkspaceItem object. @@ -49,63 +54,91 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO im @Override public List findByEPerson(Context context, EPerson ep, Integer limit, Integer offset) throws SQLException { - Criteria criteria = createCriteria(context, WorkspaceItem.class, "wi"); - criteria.addOrder(Order.asc("workspaceItemId")); - criteria.createAlias("wi.item", "item"); - criteria.createAlias("item.submitter", "submitter"); - - criteria.add(Restrictions.eq("submitter.id", ep.getID())); - criteria.setFirstResult(offset); - criteria.setMaxResults(limit); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.equal(workspaceItemRoot.get(WorkspaceItem_.item).get("submitter"), ep)); + criteriaQuery.orderBy(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + return list(context, criteriaQuery, false, WorkspaceItem.class, limit, offset); } @Override public List findByCollection(Context context, Collection c) throws SQLException { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.add(Restrictions.eq("collection", c)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.equal(workspaceItemRoot.get(WorkspaceItem_.collection), c)); + criteriaQuery.orderBy(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); } @Override public WorkspaceItem findByItem(Context context, Item i) throws SQLException { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.add(Restrictions.eq("item", i)); - // Look for the unique workspaceitem entry where 'item_id' references this item - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.equal(workspaceItemRoot.get(WorkspaceItem_.item), i)); + return uniqueResult(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); } @Override public List findAll(Context context) throws SQLException { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.addOrder(Order.asc("item")); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); } @Override public List findAll(Context context, Integer limit, Integer offset) throws SQLException { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.addOrder(Order.asc("item")); - criteria.setFirstResult(offset); - criteria.setMaxResults(limit); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, WorkspaceItem.class, limit, offset); } @Override public List findWithSupervisedGroup(Context context) throws SQLException { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.add(Restrictions.isNotEmpty("supervisorGroups")); - criteria.addOrder(Order.asc("workspaceItemId")); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.isNotEmpty(workspaceItemRoot.get(WorkspaceItem_.supervisorGroups))); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + criteriaQuery.orderBy(orderList); + return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); } @Override public List findBySupervisedGroupMember(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, WorkspaceItem.class); - criteria.createAlias("supervisorGroups", "supervisorGroup"); - criteria.createAlias("supervisorGroup.epeople", "person"); - criteria.add(Restrictions.eq("person.id", ePerson.getID())); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkspaceItem.class); + Root workspaceItemRoot = criteriaQuery.from(WorkspaceItem.class); + Join join = workspaceItemRoot.join("supervisorGroups"); + Join secondJoin = join.join("epeople"); + criteriaQuery.select(workspaceItemRoot); + criteriaQuery.where(criteriaBuilder.equal(secondJoin.get(EPerson_.id), ePerson.getID())); + criteriaQuery.orderBy(criteriaBuilder.asc(workspaceItemRoot.get(WorkspaceItem_.workspaceItemId))); + return list(context, criteriaQuery, false, WorkspaceItem.class, -1, -1); } @Override @@ -127,13 +160,13 @@ public class WorkspaceItemDAOImpl extends AbstractHibernateDAO im Query query = createQuery(context, "SELECT wi.stageReached as stage_reached, count(*) as cnt from WorkspaceItem wi" + " group by wi.stageReached order by wi.stageReached"); - query.setResultTransformer(new BasicTransformerAdapter() { - @Override - public Object transformTuple(Object[] tuple, String[] aliases) { - return new java.util.AbstractMap.SimpleImmutableEntry((Integer) tuple[0], (Long) tuple[1]); - } - }); - return (List>) query.list(); + + List list = query.getResultList(); + List> returnList = new LinkedList<>(); + for (Object[] o : list) { + returnList.add(new AbstractMap.SimpleEntry<>((Integer) o[0], (Long) o[1])); + } + return returnList; } } diff --git a/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDAO.java b/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDAO.java index 14c2622096..d4571b8463 100644 --- a/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDAO.java +++ b/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDAO.java @@ -10,21 +10,24 @@ package org.dspace.core; import java.sql.SQLException; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.UUID; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Root; -import org.apache.commons.collections4.CollectionUtils; -import org.hibernate.Criteria; -import org.hibernate.Query; +import org.apache.commons.collections.CollectionUtils; import org.hibernate.Session; -import org.hibernate.criterion.Projections; /** * Hibernate implementation for generic DAO interface. Also includes additional * Hibernate calls that are commonly used. * Each DAO should extend this class to prevent code duplication. * - * @param class type * @author kevinvandevelde at atmire.com + * @param class type */ public abstract class AbstractHibernateDAO implements GenericDAO { @@ -43,13 +46,13 @@ public abstract class AbstractHibernateDAO implements GenericDAO { //Isn't required, is just here for other DB implementation. Hibernate auto keeps track of changes. } - /** - * The Session used to manipulate entities of this type. - * - * @param context current DSpace context. - * @return the current Session. - * @throws SQLException - */ + /** + * The Session used to manipulate entities of this type. + * + * @param context current DSpace context. + * @return the current Session. + * @throws SQLException + */ protected Session getHibernateSession(Context context) throws SQLException { return ((Session) context.getDBConnection().getSession()); } @@ -61,13 +64,16 @@ public abstract class AbstractHibernateDAO implements GenericDAO { @Override public List findAll(Context context, Class clazz) throws SQLException { - return list(createCriteria(context, clazz)); + CriteriaQuery criteriaQuery = getCriteriaQuery(getCriteriaBuilder(context), clazz); + Root root = criteriaQuery.from(clazz); + criteriaQuery.select(root); + return executeCriteriaQuery(context, criteriaQuery, false, -1, -1); } @Override public T findUnique(Context context, String query) throws SQLException { @SuppressWarnings("unchecked") - T result = (T) createQuery(context, query).uniqueResult(); + T result = (T) createQuery(context, query).getSingleResult(); return result; } @@ -91,51 +97,26 @@ public abstract class AbstractHibernateDAO implements GenericDAO { @Override public List findMany(Context context, String query) throws SQLException { @SuppressWarnings("unchecked") - List result = (List) createQuery(context, query).list(); + List result = (List) createQuery(context, query).getResultList(); return result; } /** * Execute a JPA Criteria query and return a collection of results. * - * @param context The relevant DSpace Context. - * @param query JPQL query string + * @param context + * The relevant DSpace Context. + * @param query + * JPQL query string * @return list of DAOs specified by the query string * @throws SQLException if database error */ public List findMany(Context context, Query query) throws SQLException { @SuppressWarnings("unchecked") - List result = (List) query.list(); + List result = (List) query.getResultList(); return result; } - /** - * Create criteria matching an entity type or a supertype thereof. - * Use when building a criteria query. - * - * @param context current DSpace context. - * @param persistentClass specifies the type to be matched by the criteria. - * @return criteria concerning the type to be found. - * @throws SQLException passed through. - */ - public Criteria createCriteria(Context context, Class persistentClass) throws SQLException { - return getHibernateSession(context).createCriteria(persistentClass); - } - - /** - * Create criteria matching an entity type or a supertype thereof. - * Use when building a criteria query. - * - * @param context current DSpace context. - * @param persistentClass specifies the type to be matched by the criteria. - * @param alias alias for the type. - * @return criteria concerning the type to be found. - * @throws SQLException passed through. - */ - public Criteria createCriteria(Context context, Class persistentClass, String alias) throws SQLException { - return getHibernateSession(context).createCriteria(persistentClass, alias); - } - /** * Create a parsed query from a query expression. * @@ -149,82 +130,111 @@ public abstract class AbstractHibernateDAO implements GenericDAO { } /** - * Get the entities matched by the given Criteria. - * Use this if you need all results together. + * This method will return a list with unique results, no duplicates, made by the given CriteriaQuery and parameters * - * @param criteria description of desired entities. - * @return the entities matched. + * @param context + * The standard DSpace context object + * @param criteriaQuery + * The CriteriaQuery for which this list will be retrieved + * @param cacheable + * Whether or not this query should be cacheable + * @param clazz + * The clazz for which this CriteriaQuery will be executed on + * @param maxResults + * The maxmimum amount of results that will be returned for this CriteriaQuery + * @param offset + * The offset to be used for the CriteriaQuery + * @return A list of distinct results as depicted by the CriteriaQuery and parameters + * @throws SQLException */ - public List list(Criteria criteria) { + public List list(Context context, CriteriaQuery criteriaQuery, boolean cacheable, Class clazz, int maxResults, + int offset) throws SQLException { + criteriaQuery.distinct(true); @SuppressWarnings("unchecked") - List result = (List) criteria.list(); + List result = (List) executeCriteriaQuery(context, criteriaQuery, cacheable, maxResults, offset); return result; } /** - * Get the entities matching a given parsed query. - * Use this if you need all results together. + * This method will return a list of results for the given CriteriaQuery and parameters * - * @param query the query to be executed. - * @return entities matching the query. + * @param context + * The standard DSpace context object + * @param criteriaQuery + * The CriteriaQuery to be used to find the list of results + * @param cacheable + * A boolean value indicating whether this query should be cached or not + * @param clazz + * The class on which the CriteriaQuery will search + * @param maxResults + * The maximum amount of results to be returned + * @param offset + * The offset to be used for the CriteriaQuery + * @param distinct + * A boolean value indicating whether this list should be distinct or not + * @return A list of results determined by the CriteriaQuery and parameters + * @throws SQLException + */ + public List list(Context context, CriteriaQuery criteriaQuery, boolean cacheable, Class clazz, int maxResults, + int offset, boolean distinct) throws SQLException { + criteriaQuery.distinct(distinct); + @SuppressWarnings("unchecked") + List result = (List) executeCriteriaQuery(context, criteriaQuery, cacheable, maxResults, offset); + return result; + } + + /** + * This method will be used to return a list of results for the given query + * + * @param query + * The query for which the resulting list will be returned + * @return The list of results for the given query */ public List list(Query query) { @SuppressWarnings("unchecked") - List result = (List) query.list(); + List result = (List) query.getResultList(); return result; } /** - * Retrieve a unique result selected by criteria. If multiple results CAN be + * Retrieve a unique result from the query. If multiple results CAN be * retrieved an exception will be thrown, * so only use when the criteria state uniqueness in the database. - * - * @param criteria description of the desired entity. + * @param criteriaQuery JPA criteria * @return a DAO specified by the criteria */ - public T uniqueResult(Criteria criteria) { - @SuppressWarnings("unchecked") - T result = (T) criteria.uniqueResult(); - return result; - } - - /** - * Retrieve a unique result selected by a query. If multiple results CAN be - * retrieved then an exception will be thrown, so only use when the query - * states uniqueness in the database. - * - * @param query description of the desired entity. - * @return the found entity. - */ - public T uniqueResult(Query query) { - @SuppressWarnings("unchecked") - T result = (T) query.uniqueResult(); - return result; - } - - /** - * Retrieve a single result selected by criteria. Best used if you expect a - * single result, but this isn't enforced on the database. - * - * @param criteria description of the desired entities. - * @return a DAO specified by the criteria - */ - public T singleResult(Criteria criteria) { - criteria.setMaxResults(1); - List list = list(criteria); + public T uniqueResult(Context context, CriteriaQuery criteriaQuery, boolean cacheable, Class clazz, + int maxResults, int offset) throws SQLException { + List list = list(context, criteriaQuery, cacheable, clazz, maxResults, offset); if (CollectionUtils.isNotEmpty(list)) { - return list.get(0); + if (list.size() == 1) { + return list.get(0); + } else { + throw new IllegalArgumentException("More than one result found"); + } } else { return null; } } /** - * Retrieve a single result matching a query. Best used if you expect a + * Retrieve a single result from the query. Best used if you expect a * single result, but this isn't enforced on the database. + * @param criteriaQuery JPA criteria + * @return a DAO specified by the criteria + */ + public T singleResult(Context context, CriteriaQuery criteriaQuery) throws SQLException { + Query query = this.getHibernateSession(context).createQuery(criteriaQuery); + return singleResult(query); + + } + + /** + * This method will return the first result from the given query or null if no results were found * - * @param query description of desired entities. - * @return matched entities. + * @param query + * The query that is to be executed + * @return One result from the given query or null if none was found */ public T singleResult(final Query query) { query.setMaxResults(1); @@ -234,49 +244,179 @@ public abstract class AbstractHibernateDAO implements GenericDAO { } else { return null; } + } /** - * Get an iterator over a stream of query results. - * Use this when consuming results one at a time. + * This method will return a singular result for the given query * - * @param query description of desired entities. - * @return iterator over the results of the query. + * @param query + * The query for which a single result will be given + * @return The single result for this query */ - public Iterator iterate(Query query) { + public T uniqueResult(Query query) { @SuppressWarnings("unchecked") - Iterator result = (Iterator) query.iterate(); + T result = (T) query.getSingleResult(); return result; } /** - * How many rows match these criteria? - * The same value as {@link countLong(Criteria)}, coerced to {@code int}. + * This method will return an Iterator for the given Query * - * @param criteria description of the rows. - * @return count of matching rows. + * @param query + * The query for which an Iterator will be made + * @return The Iterator for the results of this query */ - public int count(Criteria criteria) { - return ((Long) criteria.setProjection(Projections.rowCount()).uniqueResult()).intValue(); + public Iterator iterate(Query query) { + @SuppressWarnings("unchecked") + Iterator result = (Iterator) query.getResultList().iterator(); + return result; } /** - * How many rows match this query? + * This method will return the amount of results that would be generated for this CriteriaQuery as an integer * - * @param query description of the rows. - * @return count of matching rows. + * @param context + * The standard DSpace Context object + * @param criteriaQuery + * The CriteriaQuery for which this result will be retrieved + * @param criteriaBuilder + * The CriteriaBuilder that accompagnies the CriteriaQuery + * @param root + * The root that'll determine on which class object we need to calculate the result + * @return The amount of results that would be found by this CriteriaQuery as an integer value + * @throws SQLException + */ + public int count(Context context, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder, Root root) + throws SQLException { + return Math.toIntExact(countLong(context, criteriaQuery, criteriaBuilder, root)); + } + + /** + * This method will return the count of items for this query as an integer + * This query needs to already be in a formate that'll return one record that contains the amount + * + * @param query + * The query for which the amount of results will be returned. + * @return The amount of results */ public int count(Query query) { - return ((Long) query.uniqueResult()).intValue(); + return ((Long) query.getSingleResult()).intValue(); } /** - * How many rows match these criteria? + * This method will return the count of items for this query as a long * - * @param criteria description of the rows. - * @return count of matching rows. + * @param context + * The standard DSpace Context object + * @param criteriaQuery + * The CriteriaQuery for which the amount of results will be retrieved + * @param criteriaBuilder + * The CriteriaBuilder that goes along with this CriteriaQuery + * @param root + * The root created for a DSpace class on which this query will search + * @return A long value that depicts the amount of results this query has found + * @throws SQLException */ - public long countLong(Criteria criteria) { - return (Long) criteria.setProjection(Projections.rowCount()).uniqueResult(); + public long countLong(Context context, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder, Root root) + throws SQLException { + Expression countExpression = criteriaBuilder.countDistinct(root); + criteriaQuery.select(countExpression); + return (Long) this.getHibernateSession(context).createQuery(criteriaQuery).getSingleResult(); } + + /** + * This method should always be used in order to retrieve the CriteriaQuery in order to + * start creating a query that has to be executed + * + * @param criteriaBuilder + * The CriteriaBuilder for which this CriteriaQuery will be constructed + * @param clazz + * The class that this CriteriaQuery will be constructed for + * @return A CriteriaQuery on which a query can be built + */ + public CriteriaQuery getCriteriaQuery(CriteriaBuilder criteriaBuilder, Class clazz) { + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(clazz); + return criteriaQuery; + } + + /** + * This method should always be used in order to retrieve a CriteriaBuilder for the given context + * + * @param context + * The standard DSpace Context class for which a CriteriaBuilder will be made + * @return A CriteriaBuilder that can be used to create the query + * @throws SQLException + */ + public CriteriaBuilder getCriteriaBuilder(Context context) throws SQLException { + return this.getHibernateSession(context).getCriteriaBuilder(); + } + + /** + * This method will return a list of objects to be returned that match the given criteriaQuery and parameters. + * The maxResults and offSet can be circumvented by entering the value -1 for them. + * + * @param context + * The standard context DSpace object + * @param criteriaQuery + * The CriteriaQuery that will be used for executing the query + * @param cacheable + * Whether or not this query is able to be cached + * @param maxResults + * The maximum amount of results that this query will return + * This can be circumvented by passing along -1 as the value + * @param offset + * The offset to be used in this query + * This can be circumvented by passing along -1 as the value + * @return This will return a list of objects that conform to the made query + * @throws SQLException + */ + public List executeCriteriaQuery(Context context, CriteriaQuery criteriaQuery, boolean cacheable, + int maxResults, int offset) throws SQLException { + Query query = this.getHibernateSession(context).createQuery(criteriaQuery); + + query.setHint("org.hibernate.cacheable", cacheable); + if (maxResults != -1) { + query.setMaxResults(maxResults); + } + if (offset != -1) { + query.setFirstResult(offset); + } + return query.getResultList(); + + } + + /** + * This method can be used to construct a query for which there needs to be a bunch of equal properties + * These properties can be passed along in the equals hashmap + * + * @param context + * The standard DSpace context object + * @param clazz + * The class on which the criteriaQuery will be built + * @param equals + * A hashmap that can be used to store the String representation of the column + * and the value that should match that in the DB + * @param cacheable + * A boolean indicating whether this query should be cacheable or not + * @param maxResults + * The max amount of results to be returned by this query + * @param offset + * The offset to be used in this query + * @return Will return a list of objects that correspond with the constructed query and parameters + * @throws SQLException + */ + public List findByX(Context context, Class clazz, Map equals, boolean cacheable, int maxResults, + int offset) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteria = getCriteriaQuery(criteriaBuilder, clazz); + Root root = criteria.from(clazz); + criteria.select(root); + + for (Map.Entry entry : equals.entrySet()) { + criteria.where(criteriaBuilder.equal(root.get(entry.getKey()), entry.getValue())); + } + return executeCriteriaQuery(context, criteria, cacheable, maxResults, offset); + } + } diff --git a/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDSODAO.java b/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDSODAO.java index c17d1bdb86..232431cac7 100644 --- a/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDSODAO.java +++ b/dspace-api/src/main/java/org/dspace/core/AbstractHibernateDSODAO.java @@ -9,15 +9,16 @@ package org.dspace.core; import java.sql.SQLException; import java.util.Collection; -import java.util.Collections; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; -import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.ListUtils; import org.apache.commons.lang3.StringUtils; import org.dspace.content.DSpaceObject; import org.dspace.content.MetadataField; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation used by DSpaceObject Database Access Objects. @@ -26,8 +27,8 @@ import org.hibernate.criterion.Restrictions; *

* Each DSO Database Access Object should extend this class to prevent code duplication. * - * @param type of DSO represented. * @author kevinvandevelde at atmire.com + * @param type of DSO represented. */ public abstract class AbstractHibernateDSODAO extends AbstractHibernateDAO { /** @@ -36,27 +37,27 @@ public abstract class AbstractHibernateDSODAO extends Ab * All DSOs now have UUID primary keys, and those should be used when available. * Each type derived from DSpaceObject had its own stream of record IDs, so * it is also necessary to know the specific type. - * - * @param context current DSpace context. + * @param context current DSpace context. * @param legacyId the old integer record identifier. - * @param clazz DSO subtype of record identified by {@link legacyId}. + * @param clazz DSO subtype of record identified by {@link legacyId}. * @return * @throws SQLException */ public T findByLegacyId(Context context, int legacyId, Class clazz) throws SQLException { - Criteria criteria = createCriteria(context, clazz); - criteria.add(Restrictions.eq("legacyId", legacyId)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, clazz); + Root root = criteriaQuery.from(clazz); + criteriaQuery.where(criteriaBuilder.equal(root.get("legacyId"), legacyId)); + return uniqueResult(context, criteriaQuery, false, clazz, -1, -1); } /** * Add left outer join on all metadata fields which are passed to this function. * The identifier of the join will be the toString() representation of the metadata field. * The joined metadata fields can then be used to query or sort. - * - * @param query the query string being built. + * @param query the query string being built. * @param tableIdentifier name of the table to be joined. - * @param metadataFields names of the desired fields. + * @param metadataFields names of the desired fields. */ protected void addMetadataLeftJoin(StringBuilder query, String tableIdentifier, Collection metadataFields) { @@ -72,9 +73,9 @@ public abstract class AbstractHibernateDSODAO extends Ab * Values can be checked using a like or an "=" query, as determined by the "operator" parameter. * When creating a query, the "queryParam" string can be used set as parameter for the query. * - * @param query the already existing query builder, all changes will be appended - * @param metadataFields the metadata fields whose metadata value should be queried - * @param operator can either be "=" or "like" + * @param query the already existing query builder, all changes will be appended + * @param metadataFields the metadata fields whose metadata value should be queried + * @param operator can either be "=" or "like" * @param additionalWhere additional where query */ protected void addMetadataValueWhereQuery(StringBuilder query, List metadataFields, String operator, @@ -108,23 +109,21 @@ public abstract class AbstractHibernateDSODAO extends Ab /** * Append ORDER BY clause based on metadata fields or column names. * All fields will be in ascending order. - * - * @param query the query being built. + * @param query the query being built. * @param metadataSortFields fields on which to sort -- use this OR columnSortFields. - * @param columnSortFields columns on which to sort -- use this OR metadataSortFields. + * @param columnSortFields columns on which to sort -- use this OR metadataSortFields. */ protected void addMetadataSortQuery(StringBuilder query, List metadataSortFields, List columnSortFields) { - addMetadataSortQuery(query, metadataSortFields, columnSortFields, Collections.EMPTY_LIST); + addMetadataSortQuery(query, metadataSortFields, columnSortFields, ListUtils.EMPTY_LIST); } /** * Append ORDER BY clause based on metadata fields or column names. - * - * @param query the query being built. + * @param query the query being built. * @param metadataSortFields fields on which to sort -- use this OR columnSortFields. - * @param columnSortFields columns on which to sort -- use this OR metadataSortFields. - * @param direction ASC or DESC for each field. Unspecified fields will be ASC. + * @param columnSortFields columns on which to sort -- use this OR metadataSortFields. + * @param direction ASC or DESC for each field. Unspecified fields will be ASC. */ protected void addMetadataSortQuery(StringBuilder query, List metadataSortFields, List columnSortFields, List direction) { diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/EPersonDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/EPersonDAOImpl.java index 581393e686..fd4c6f59d9 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/EPersonDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/EPersonDAOImpl.java @@ -15,18 +15,21 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import java.util.UUID; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; -import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.ListUtils; import org.apache.commons.lang3.StringUtils; import org.dspace.content.MetadataField; import org.dspace.core.AbstractHibernateDSODAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; +import org.dspace.eperson.EPerson_; import org.dspace.eperson.Group; import org.dspace.eperson.dao.EPersonDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the EPerson object. @@ -42,22 +45,23 @@ public class EPersonDAOImpl extends AbstractHibernateDSODAO implements @Override public EPerson findByEmail(Context context, String email) throws SQLException { - // All email addresses are stored as lowercase, so ensure that the email address is lowercased for the lookup - Criteria criteria = createCriteria(context, EPerson.class); - criteria.add(Restrictions.eq("email", email.toLowerCase())); - - criteria.setCacheable(true); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EPerson.class); + Root ePersonRoot = criteriaQuery.from(EPerson.class); + criteriaQuery.select(ePersonRoot); + criteriaQuery.where(criteriaBuilder.equal(ePersonRoot.get(EPerson_.email), email.toLowerCase())); + return uniqueResult(context, criteriaQuery, true, EPerson.class, -1, -1); } @Override public EPerson findByNetid(Context context, String netid) throws SQLException { - Criteria criteria = createCriteria(context, EPerson.class); - criteria.add(Restrictions.eq("netid", netid)); - - criteria.setCacheable(true); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EPerson.class); + Root ePersonRoot = criteriaQuery.from(EPerson.class); + criteriaQuery.select(ePersonRoot); + criteriaQuery.where((criteriaBuilder.equal(ePersonRoot.get(EPerson_.netid), netid))); + return uniqueResult(context, criteriaQuery, true, EPerson.class, -1, -1); } @Override @@ -101,8 +105,8 @@ public class EPersonDAOImpl extends AbstractHibernateDSODAO implements sortFields = Collections.singletonList(metadataSortField); } - Query query = getSearchQuery(context, queryString, null, Collections.EMPTY_LIST, sortFields, - sortField, pageSize, offset); + Query query = getSearchQuery(context, queryString, null, ListUtils.EMPTY_LIST, sortFields, sortField, pageSize, + offset); return list(query); } @@ -119,26 +123,32 @@ public class EPersonDAOImpl extends AbstractHibernateDSODAO implements idList.add(group.getID()); } - query.setParameterList("idList", idList); + query.setParameter("idList", idList); return list(query); } @Override public List findWithPasswordWithoutDigestAlgorithm(Context context) throws SQLException { - Criteria criteria = createCriteria(context, EPerson.class); - criteria.add(Restrictions.and( - Restrictions.isNotNull("password"), - Restrictions.isNull("digestAlgorithm") - )); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EPerson.class); + Root ePersonRoot = criteriaQuery.from(EPerson.class); + criteriaQuery.select(ePersonRoot); + criteriaQuery.where(criteriaBuilder.and(criteriaBuilder.isNotNull(ePersonRoot.get(EPerson_.password)), + criteriaBuilder.isNull(ePersonRoot.get(EPerson_.digestAlgorithm)) + ) + ); + return list(context, criteriaQuery, false, EPerson.class, -1, -1); } @Override public List findNotActiveSince(Context context, Date date) throws SQLException { - Criteria criteria = createCriteria(context, EPerson.class); - criteria.add(Restrictions.le("lastActive", date)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, EPerson.class); + Root ePersonRoot = criteriaQuery.from(EPerson.class); + criteriaQuery.select(ePersonRoot); + criteriaQuery.where(criteriaBuilder.lessThanOrEqualTo(ePersonRoot.get(EPerson_.lastActive), date)); + return list(context, criteriaQuery, false, EPerson.class, -1, -1); } protected Query getSearchQuery(Context context, String queryString, String queryParam, diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/Group2GroupCacheDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/Group2GroupCacheDAOImpl.java index 03858e2240..717b41e8b9 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/Group2GroupCacheDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/Group2GroupCacheDAOImpl.java @@ -8,17 +8,20 @@ package org.dspace.eperson.dao.impl; import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.Group; import org.dspace.eperson.Group2GroupCache; +import org.dspace.eperson.Group2GroupCache_; import org.dspace.eperson.dao.Group2GroupCacheDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the Group2GroupCache object. @@ -34,26 +37,27 @@ public class Group2GroupCacheDAOImpl extends AbstractHibernateDAO findByParent(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, Group2GroupCache.class); - criteria.add(Restrictions.eq("parent.id", group.getID())); - criteria.setCacheable(true); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Group2GroupCache.class); + Root group2GroupCacheRoot = criteriaQuery.from(Group2GroupCache.class); + criteriaQuery.select(group2GroupCacheRoot); + criteriaQuery.where(criteriaBuilder.equal(group2GroupCacheRoot.get(Group2GroupCache_.parent), group)); + return list(context, criteriaQuery, true, Group2GroupCache.class, -1, -1); } @Override public List findByChildren(Context context, Iterable groups) throws SQLException { - Criteria criteria = createCriteria(context, Group2GroupCache.class); - - Disjunction orDisjunction = Restrictions.or(); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Group2GroupCache.class); + Root group2GroupCacheRoot = criteriaQuery.from(Group2GroupCache.class); + List eqPredicates = new LinkedList<>(); for (Group group : groups) { - orDisjunction.add(Restrictions.eq("child.id", group.getID())); + eqPredicates.add(criteriaBuilder.equal(group2GroupCacheRoot.get(Group2GroupCache_.child), group)); } - - criteria.add(orDisjunction); - criteria.setCacheable(true); - - return list(criteria); + Predicate orPredicate = criteriaBuilder.or(eqPredicates.toArray(new Predicate[] {})); + criteriaQuery.select(group2GroupCacheRoot); + criteriaQuery.where(orPredicate); + return list(context, criteriaQuery, true, Group2GroupCache.class, -1, -1); } @Override @@ -63,19 +67,23 @@ public class Group2GroupCacheDAOImpl extends AbstractHibernateDAO group2GroupCacheRoot = criteriaQuery.from(Group2GroupCache.class); + criteriaQuery.select(group2GroupCacheRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(group2GroupCacheRoot.get(Group2GroupCache_.parent), parent), + criteriaBuilder.equal(group2GroupCacheRoot.get(Group2GroupCache_.child), child) + ) + ); + return uniqueResult(context, criteriaQuery, true, Group2GroupCache.class, -1, -1); } @Override diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/GroupDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/GroupDAOImpl.java index e61f28b7f5..8050bd9755 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/GroupDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/GroupDAOImpl.java @@ -11,6 +11,7 @@ import java.sql.SQLException; import java.util.Collections; import java.util.List; import java.util.UUID; +import javax.persistence.Query; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.Pair; @@ -20,7 +21,6 @@ import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.eperson.dao.GroupDAO; -import org.hibernate.Query; /** * Hibernate implementation of the Database Access Object interface class for the Group object. @@ -84,7 +84,7 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou if (offset > 0) { query.setFirstResult(offset); } - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return list(query); } @@ -94,7 +94,7 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou Query query = createQuery(context, "from Group where (from EPerson e where e.id = :eperson_id) in elements(epeople)"); query.setParameter("eperson_id", ePerson.getID()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return list(query); } @@ -106,7 +106,7 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou "where g.name = :name "); query.setParameter("name", name); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query); } @@ -132,7 +132,7 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou query.setParameter("id", id); query.setParameter("eperson_id", ePerson.getID()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return singleResult(query); } @@ -182,7 +182,7 @@ public class GroupDAOImpl extends AbstractHibernateDSODAO implements Grou "JOIN g.groups c "); @SuppressWarnings("unchecked") - List> results = query.list(); + List> results = query.getResultList(); return results; } diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/RegistrationDataDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/RegistrationDataDAOImpl.java index c5aa36b5a4..35fda4b62f 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/RegistrationDataDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/RegistrationDataDAOImpl.java @@ -8,14 +8,16 @@ package org.dspace.eperson.dao.impl; import java.sql.SQLException; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.RegistrationData; +import org.dspace.eperson.RegistrationData_; import org.dspace.eperson.dao.RegistrationDataDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the RegistrationData object. @@ -32,16 +34,22 @@ public class RegistrationDataDAOImpl extends AbstractHibernateDAO registrationDataRoot = criteriaQuery.from(RegistrationData.class); + criteriaQuery.select(registrationDataRoot); + criteriaQuery.where(criteriaBuilder.equal(registrationDataRoot.get(RegistrationData_.email), email)); + return uniqueResult(context, criteriaQuery, false, RegistrationData.class, -1, -1); } @Override public RegistrationData findByToken(Context context, String token) throws SQLException { - Criteria criteria = createCriteria(context, RegistrationData.class); - criteria.add(Restrictions.eq("token", token)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, RegistrationData.class); + Root registrationDataRoot = criteriaQuery.from(RegistrationData.class); + criteriaQuery.select(registrationDataRoot); + criteriaQuery.where(criteriaBuilder.equal(registrationDataRoot.get(RegistrationData_.token), token)); + return uniqueResult(context, criteriaQuery, false, RegistrationData.class, -1, -1); } @Override diff --git a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java index 88734410e1..a90c5da5a1 100644 --- a/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/eperson/dao/impl/SubscriptionDAOImpl.java @@ -8,18 +8,20 @@ package org.dspace.eperson.dao.impl; import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.Collection; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Subscription; +import org.dspace.eperson.Subscription_; import org.dspace.eperson.dao.SubscriptionDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the Subscription object. @@ -35,27 +37,28 @@ public class SubscriptionDAOImpl extends AbstractHibernateDAO impl @Override public List findByEPerson(Context context, EPerson eperson) throws SQLException { - Criteria criteria = createCriteria(context, Subscription.class); - criteria.add( - Restrictions.and( - Restrictions.eq("ePerson", eperson) - ) - ); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + javax.persistence.criteria.CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class); + Root subscriptionRoot = criteriaQuery.from(Subscription.class); + criteriaQuery.select(subscriptionRoot); + criteriaQuery.where(criteriaBuilder.equal(subscriptionRoot.get(Subscription_.ePerson), eperson)); + return list(context, criteriaQuery, false, Subscription.class, -1, -1); } @Override public Subscription findByCollectionAndEPerson(Context context, EPerson eperson, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, Subscription.class); - criteria.add( - Restrictions.and( - Restrictions.eq("ePerson", eperson), - Restrictions.eq("collection", collection) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + javax.persistence.criteria.CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class); + Root subscriptionRoot = criteriaQuery.from(Subscription.class); + criteriaQuery.select(subscriptionRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(subscriptionRoot.get(Subscription_.ePerson), eperson), + criteriaBuilder.equal(subscriptionRoot.get(Subscription_.collection), collection) + ) ); - return singleResult(criteria); + return singleResult(context, criteriaQuery); } @@ -87,8 +90,17 @@ public class SubscriptionDAOImpl extends AbstractHibernateDAO impl @Override public List findAllOrderedByEPerson(Context context) throws SQLException { - Criteria criteria = createCriteria(context, Subscription.class); - criteria.addOrder(Order.asc("ePerson")); - return list(criteria); + + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Subscription.class); + Root subscriptionRoot = criteriaQuery.from(Subscription.class); + criteriaQuery.select(subscriptionRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(subscriptionRoot.get(Subscription_.ePerson))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, false, Subscription.class, -1, -1); } -} +} \ No newline at end of file diff --git a/dspace-api/src/main/java/org/dspace/handle/dao/impl/HandleDAOImpl.java b/dspace-api/src/main/java/org/dspace/handle/dao/impl/HandleDAOImpl.java index 1aac41a144..3bd702bf80 100644 --- a/dspace-api/src/main/java/org/dspace/handle/dao/impl/HandleDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/handle/dao/impl/HandleDAOImpl.java @@ -13,15 +13,17 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.DSpaceObject; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.handle.Handle; +import org.dspace.handle.Handle_; import org.dspace.handle.dao.HandleDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.dialect.internal.StandardDialectResolver; import org.hibernate.engine.jdbc.dialect.spi.DatabaseMetaDataDialectResolutionInfoAdapter; @@ -56,7 +58,7 @@ public class HandleDAOImpl extends AbstractHibernateDAO implements Handl query.setParameter("id", dso.getID()); - query.setCacheable(true); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); return list(query); } } @@ -71,22 +73,32 @@ public class HandleDAOImpl extends AbstractHibernateDAO implements Handl query.setParameter("handle", handle); - query.setCacheable(true); - return uniqueResult(query); + query.setHint("org.hibernate.cacheable", Boolean.TRUE); + return singleResult(query); } @Override public List findByPrefix(Context context, String prefix) throws SQLException { - Criteria criteria = createCriteria(context, Handle.class); - criteria.add(Restrictions.like("handle", prefix + "%")); - return list(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Handle.class); + Root handleRoot = criteriaQuery.from(Handle.class); + criteriaQuery.select(handleRoot); + criteriaQuery.where(criteriaBuilder.like(handleRoot.get(Handle_.handle), prefix + "%")); + return list(context, criteriaQuery, false, Handle.class, -1, -1); } @Override public long countHandlesByPrefix(Context context, String prefix) throws SQLException { - Criteria criteria = createCriteria(context, Handle.class); - criteria.add(Restrictions.like("handle", prefix + "%")); - return countLong(criteria); + + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root handleRoot = criteriaQuery.from(Handle.class); + criteriaQuery.select(criteriaBuilder.count(criteriaQuery.from(Handle.class))); + criteriaQuery.where(criteriaBuilder.like(handleRoot.get(Handle_.handle), prefix + "%")); + return countLong(context, criteriaQuery, criteriaBuilder, handleRoot); } @Override @@ -94,9 +106,9 @@ public class HandleDAOImpl extends AbstractHibernateDAO implements Handl String hql = "UPDATE Handle set handle = concat(:newPrefix, '/', substring(handle, :oldPrefixLength + 2)) " + "WHERE handle like concat(:oldPrefix,'%')"; Query query = createQuery(context, hql); - query.setString("newPrefix", newPrefix); - query.setInteger("oldPrefixLength", oldPrefix.length()); - query.setString("oldPrefix", oldPrefix); + query.setParameter("newPrefix", newPrefix); + query.setParameter("oldPrefixLength", oldPrefix.length()); + query.setParameter("oldPrefix", oldPrefix); return query.executeUpdate(); } @@ -107,7 +119,6 @@ public class HandleDAOImpl extends AbstractHibernateDAO implements Handl /** * Return next available value of Handle suffix (based on DB sequence). - * * @param context Current DSpace Context * @return next available Handle suffix (as a Long) * @throws SQLException if database error or sequence doesn't exist diff --git a/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedCollectionDAOImpl.java b/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedCollectionDAOImpl.java index aee60639c3..95a0bdf216 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedCollectionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedCollectionDAOImpl.java @@ -9,18 +9,19 @@ package org.dspace.harvest.dao.impl; import java.sql.SQLException; import java.util.Date; +import java.util.LinkedList; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; import org.dspace.content.Collection; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.harvest.HarvestedCollection; +import org.dspace.harvest.HarvestedCollection_; import org.dspace.harvest.dao.HarvestedCollectionDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.LogicalExpression; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the HarvestedCollection object. @@ -39,98 +40,136 @@ public class HarvestedCollectionDAOImpl extends AbstractHibernateDAO ? and harvest_status = ? -// order by last_harvested desc limit 1"; - Criteria criteria = getByStatusAndMinimalTypeCriteria(context, status, type, limit); - criteria.addOrder(Order.desc("lastHarvested")); - return singleResult(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.desc(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested))); + criteriaQuery.orderBy(orderList); + + return singleResult(context, criteriaQuery); } @Override public HarvestedCollection findByStatusAndMinimalTypeOrderByLastHarvestedAsc(Context context, int status, int type, int limit) throws SQLException { -// Old query: "select collection_id from harvested_collection where harvest_type > ? and harvest_status = ? -// order by last_harvested asc limit 1"; - Criteria criteria = getByStatusAndMinimalTypeCriteria(context, status, type, limit); - criteria.addOrder(Order.asc("lastHarvested")); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested))); + criteriaQuery.orderBy(orderList); + + return singleResult(context, criteriaQuery); } @Override public List findByStatus(Context context, int status) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedCollection.class); - criteria.add(Restrictions.eq("harvestStatus", status)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + criteriaQuery + .where(criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.harvestStatus), status)); + return list(context, criteriaQuery, false, HarvestedCollection.class, -1, -1); } @Override public HarvestedCollection findByCollection(Context context, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedCollection.class); - criteria.add(Restrictions.eq("collection", collection)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + criteriaQuery + .where(criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.collection), collection)); + return singleResult(context, criteriaQuery); } @Override public List - findByLastHarvestedAndHarvestTypeAndHarvestStatusesAndHarvestTime(Context context, Date startTime, - int minimalType, int[] statuses, - int expirationStatus, Date expirationTime) + findByLastHarvestedAndHarvestTypeAndHarvestStatusesAndHarvestTime(Context context, + Date startTime, + int minimalType, + int[] statuses, + int expirationStatus, + Date expirationTime) throws SQLException { -// Old query: "SELECT * FROM harvested_collection WHERE -// (last_harvested < ? or last_harvested is null) and harvest_type > ? and (harvest_status = ? or harvest_status = ? -// or (harvest_status=? and harvest_start_time < ?)) ORDER BY last_harvested", -// new java.sql.Timestamp(startTime.getTime()), 0, HarvestedCollection.STATUS_READY, -// HarvestedCollection.STATUS_OAI_ERROR, HarvestedCollection.STATUS_BUSY, new java.sql.Timestamp(expirationTime -// .getTime())); - Criteria criteria = createCriteria(context, HarvestedCollection.class); - LogicalExpression lastHarvestedRestriction = Restrictions.or( - Restrictions.lt("lastHarvested", startTime), - Restrictions.isNull("lastHarvested") - ); - Disjunction statusRestriction = Restrictions.or(); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + + Predicate wasNotHarvestedInCurrentRun = criteriaBuilder + .or(criteriaBuilder.lessThan(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested), startTime), + criteriaBuilder.isNull(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested)) + ); + + List hasCorrectStatusOrIsExpiredRestrictions = new LinkedList<>(); + for (int status : statuses) { - statusRestriction.add(Restrictions.eq("harvestStatus", status)); + hasCorrectStatusOrIsExpiredRestrictions + .add(criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.harvestStatus), status)); } - statusRestriction.add( - Restrictions.and( - Restrictions.eq("harvestStatus", expirationStatus), - Restrictions.gt("harvestStartTime", expirationTime) - ) + + Predicate harvestExpiredRestriction = criteriaBuilder.and( + criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.harvestStatus), expirationStatus), + criteriaBuilder + .greaterThan(harvestedCollectionRoot.get(HarvestedCollection_.harvestStartTime), expirationTime) ); - criteria.add( - Restrictions.and( - lastHarvestedRestriction, - Restrictions.gt("harvestType", minimalType), - statusRestriction + hasCorrectStatusOrIsExpiredRestrictions.add(harvestExpiredRestriction); - ) + Predicate hasCorrectStatusOrIsExpiredPredicate = criteriaBuilder.or(hasCorrectStatusOrIsExpiredRestrictions + .toArray(new Predicate[] {})); + + Predicate hasMinimalType = criteriaBuilder.greaterThan( + harvestedCollectionRoot.get(HarvestedCollection_.harvestType), + minimalType); + + criteriaQuery.where(criteriaBuilder.and(wasNotHarvestedInCurrentRun, + hasMinimalType, + hasCorrectStatusOrIsExpiredPredicate + ) ); - criteria.addOrder(Order.asc("lastHarvested")); - return list(criteria); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(harvestedCollectionRoot.get(HarvestedCollection_.lastHarvested))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, HarvestedCollection.class, -1, -1); + } @Override public int count(Context context) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedCollection.class); - return count(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + return count(context, criteriaQuery, criteriaBuilder, harvestedCollectionRoot); } - protected Criteria getByStatusAndMinimalTypeCriteria(Context context, int status, int type, int limit) + protected CriteriaQuery getByStatusAndMinimalTypeCriteria(Context context, int status, int type) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedCollection.class); - criteria.add( - Restrictions.and( - Restrictions.gt("harvestType", type), - Restrictions.eq("harvestStatus", status) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedCollection.class); + Root harvestedCollectionRoot = criteriaQuery.from(HarvestedCollection.class); + criteriaQuery.select(harvestedCollectionRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.greaterThan(harvestedCollectionRoot.get(HarvestedCollection_.harvestType), type), + criteriaBuilder.equal(harvestedCollectionRoot.get(HarvestedCollection_.harvestStatus), status) + ) ); - if (limit != -1) { - criteria.setMaxResults(1); - } - return criteria; + return criteriaQuery; } } diff --git a/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedItemDAOImpl.java index 73ed113b70..9e9838be6c 100644 --- a/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/harvest/dao/impl/HarvestedItemDAOImpl.java @@ -8,15 +8,19 @@ package org.dspace.harvest.dao.impl; import java.sql.SQLException; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; import org.dspace.content.Collection; import org.dspace.content.Item; +import org.dspace.content.Item_; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.harvest.HarvestedItem; +import org.dspace.harvest.HarvestedItem_; import org.dspace.harvest.dao.HarvestedItemDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the HarvestedItem object. @@ -32,21 +36,28 @@ public class HarvestedItemDAOImpl extends AbstractHibernateDAO im @Override public HarvestedItem findByItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedItem.class); - criteria.add(Restrictions.eq("item", item)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedItem.class); + Root harvestedItemRoot = criteriaQuery.from(HarvestedItem.class); + criteriaQuery.select(harvestedItemRoot); + criteriaQuery.where(criteriaBuilder.equal(harvestedItemRoot.get(HarvestedItem_.item), item)); + return singleResult(context, criteriaQuery); } @Override public HarvestedItem findByOAIId(Context context, String itemOaiID, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, HarvestedItem.class); - criteria.createAlias("item", "i"); - criteria.add( - Restrictions.and( - Restrictions.eq("oaiId", itemOaiID), - Restrictions.eq("i.owningCollection", collection) - ) + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, HarvestedItem.class); + Root harvestedItemRoot = criteriaQuery.from(HarvestedItem.class); + Join join = harvestedItemRoot.join("item"); + criteriaQuery.select(harvestedItemRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(harvestedItemRoot.get(HarvestedItem_.oaiId), itemOaiID), + criteriaBuilder.equal(join.get(Item_.owningCollection), collection) + ) ); - return singleResult(criteria); + return singleResult(context, criteriaQuery); + } } diff --git a/dspace-api/src/main/java/org/dspace/identifier/dao/impl/DOIDAOImpl.java b/dspace-api/src/main/java/org/dspace/identifier/dao/impl/DOIDAOImpl.java index f62cf0e99e..019e89c129 100644 --- a/dspace-api/src/main/java/org/dspace/identifier/dao/impl/DOIDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/identifier/dao/impl/DOIDAOImpl.java @@ -8,17 +8,19 @@ package org.dspace.identifier.dao.impl; import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; import org.dspace.content.DSpaceObject; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.identifier.DOI; +import org.dspace.identifier.DOI_; import org.dspace.identifier.dao.DOIDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Conjunction; -import org.hibernate.criterion.Disjunction; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the DOI object. @@ -34,74 +36,88 @@ public class DOIDAOImpl extends AbstractHibernateDAO implements DOIDAO { @Override public DOI findByDoi(Context context, String doi) throws SQLException { - Criteria criteria = createCriteria(context, DOI.class); - criteria.add(Restrictions.eq("doi", doi)); - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); + criteriaQuery.where(criteriaBuilder.equal(doiRoot.get(DOI_.doi), doi)); + return uniqueResult(context, criteriaQuery, false, DOI.class, -1, -1); } @Override public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso, List statusToExclude) throws SQLException { - //SELECT * FROM Doi WHERE resource_type_id = ? AND resource_id = ? AND resource_id = ? AND ((status != ? AND - // status != ?) OR status IS NULL) - Criteria criteria = createCriteria(context, DOI.class); - Disjunction statusQuery = Restrictions.or(); - Conjunction statusConjunctionAnd = Restrictions.and(); - for (Integer status : statusToExclude) { - statusConjunctionAnd.add(Restrictions.not(Restrictions.eq("status", status))); - } - statusQuery.add(statusConjunctionAnd); - statusQuery.add(Restrictions.isNull("status")); - criteria.add( - Restrictions.and( - Restrictions.eq("dSpaceObject", dso), - statusQuery + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); - ) + List listToIncludeInOrPredicate = new LinkedList<>(); + + for (Integer status : statusToExclude) { + listToIncludeInOrPredicate.add(criteriaBuilder.notEqual(doiRoot.get(DOI_.status), status)); + } + listToIncludeInOrPredicate.add(criteriaBuilder.isNull(doiRoot.get(DOI_.status))); + + Predicate orPredicate = criteriaBuilder.or(listToIncludeInOrPredicate.toArray(new Predicate[] {})); + + criteriaQuery.where(criteriaBuilder.and(orPredicate, + criteriaBuilder.equal(doiRoot.get(DOI_.dSpaceObject), dso) + ) ); - return singleResult(criteria); + + return singleResult(context, criteriaQuery); } @Override public List findByStatus(Context context, List statuses) throws SQLException { - Criteria criteria = createCriteria(context, DOI.class); - Disjunction statusQuery = Restrictions.or(); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); + List orPredicates = new LinkedList<>(); for (Integer status : statuses) { - statusQuery.add(Restrictions.eq("status", status)); + orPredicates.add(criteriaBuilder.equal(doiRoot.get(DOI_.status), status)); } - criteria.add(statusQuery); - return list(criteria); + criteriaQuery.where(criteriaBuilder.or(orPredicates.toArray(new Predicate[] {}))); + return list(context, criteriaQuery, false, DOI.class, -1, -1); } @Override public List findSimilarNotInState(Context context, String doi, List excludedStatuses, boolean dsoNotNull) throws SQLException { - // SELECT * FROM Doi WHERE doi LIKE ? AND resource_type_id = ? AND resource_id IS NOT NULL AND status != ? - // AND status != ? - Criteria criteria = createCriteria(context, DOI.class); - Conjunction conjunctionAnd = Restrictions.and(); - Disjunction statusQuery = Restrictions.or(); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); + + List listToIncludeInOrPredicate = new LinkedList<>(); + for (Integer status : excludedStatuses) { - statusQuery.add(Restrictions.ne("status", status)); + listToIncludeInOrPredicate.add(criteriaBuilder.notEqual(doiRoot.get(DOI_.status), status)); } - conjunctionAnd.add(Restrictions.like("doi", doi)); - conjunctionAnd.add(statusQuery); + + List listToIncludeInAndPredicate = new LinkedList<>(); + + listToIncludeInAndPredicate.add(criteriaBuilder.like(doiRoot.get(DOI_.doi), doi)); + listToIncludeInAndPredicate.add(criteriaBuilder.or(listToIncludeInOrPredicate.toArray(new Predicate[] {}))); if (dsoNotNull) { - conjunctionAnd.add(Restrictions.isNotNull("dSpaceObject")); + listToIncludeInAndPredicate.add(criteriaBuilder.isNotNull(doiRoot.get(DOI_.dSpaceObject))); } - criteria.add(conjunctionAnd); - return list(criteria); + criteriaQuery.where(listToIncludeInAndPredicate.toArray(new Predicate[] {})); + return list(context, criteriaQuery, false, DOI.class, -1, -1); + + } @Override public DOI findDOIByDSpaceObject(Context context, DSpaceObject dso) throws SQLException { - Criteria criteria = createCriteria(context, DOI.class); - criteria.add( - Restrictions.and( - Restrictions.eq("dSpaceObject", dso) - ) - ); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, DOI.class); + Root doiRoot = criteriaQuery.from(DOI.class); + criteriaQuery.select(doiRoot); + criteriaQuery.where(criteriaBuilder.equal(doiRoot.get(DOI_.dSpaceObject), dso)); + return singleResult(context, criteriaQuery); } } diff --git a/dspace-api/src/main/java/org/dspace/submit/extraction/MetadataExtractor.java b/dspace-api/src/main/java/org/dspace/submit/extraction/MetadataExtractor.java index ccaa6e05d1..0961a49d92 100644 --- a/dspace-api/src/main/java/org/dspace/submit/extraction/MetadataExtractor.java +++ b/dspace-api/src/main/java/org/dspace/submit/extraction/MetadataExtractor.java @@ -13,7 +13,11 @@ import gr.ekt.bte.dataloader.FileDataLoader; import org.dspace.services.ConfigurationService; /** + * Configuration bean to associate a BTE FileDataLoader with a specific list of format identified by the file + * extensions. See config/spring/api/metadata-extractor.xml + * * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + * @author Andrea Bollini (andrea.bollini at 4science.it) */ public class MetadataExtractor { diff --git a/dspace-api/src/main/java/org/dspace/submit/listener/MetadataListener.java b/dspace-api/src/main/java/org/dspace/submit/listener/MetadataListener.java index ddc8c04ae0..df3c78919e 100644 --- a/dspace-api/src/main/java/org/dspace/submit/listener/MetadataListener.java +++ b/dspace-api/src/main/java/org/dspace/submit/listener/MetadataListener.java @@ -12,12 +12,26 @@ import java.util.Map; import gr.ekt.bte.core.DataLoader; import org.dspace.services.ConfigurationService; +/** + * Configuration bean to map metadata to identifiers (i.e dc.identifier.doi -> doi, dc.identifier.isbn -> isbn) and + * alias to BTE Data Loader. See config/spring/api/step-processing.xml + * + * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + * @author Andrea Bollini (andrea.bollini at 4science.it) + * + */ public class MetadataListener { + /** + * Metadata to identifier map + */ private Map metadata; private ConfigurationService configurationService; + /** + * Alias to data loader map + */ private Map dataloadersMap; public ConfigurationService getConfigurationService() { diff --git a/dspace-api/src/main/java/org/dspace/submit/step/MetadataStep.java b/dspace-api/src/main/java/org/dspace/submit/step/MetadataStep.java index 1c8b411eb5..c0998bcb2e 100644 --- a/dspace-api/src/main/java/org/dspace/submit/step/MetadataStep.java +++ b/dspace-api/src/main/java/org/dspace/submit/step/MetadataStep.java @@ -33,6 +33,7 @@ import org.dspace.submit.AbstractProcessingStep; import org.dspace.submit.listener.MetadataListener; import org.dspace.submit.lookup.SubmissionLookupDataLoader; +//FIXME move to the ExtractionStep /** * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) */ diff --git a/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionDAOImpl.java b/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionDAOImpl.java index d93026bd44..6633c892ea 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionDAOImpl.java @@ -8,18 +8,20 @@ package org.dspace.versioning.dao.impl; import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.Item; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.versioning.Version; import org.dspace.versioning.VersionHistory; +import org.dspace.versioning.Version_; import org.dspace.versioning.dao.VersionDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the Version object. @@ -39,9 +41,12 @@ public class VersionDAOImpl extends AbstractHibernateDAO implements Ver @Override public Version findByItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, Version.class); - criteria.add(Restrictions.eq("item", item)); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Version.class); + Root versionRoot = criteriaQuery.from(Version.class); + criteriaQuery.select(versionRoot); + criteriaQuery.where(criteriaBuilder.equal(versionRoot.get(Version_.item), item)); + return singleResult(context, criteriaQuery); } @Override @@ -51,17 +56,28 @@ public class VersionDAOImpl extends AbstractHibernateDAO implements Ver + "FROM Version WHERE versionHistory.id = :historyId"); q.setParameter("historyId", vh.getID()); - int next = (Integer) q.uniqueResult(); + int next = (Integer) q.getSingleResult(); return next; } @Override public List findVersionsWithItems(Context context, VersionHistory versionHistory) throws SQLException { - Criteria criteria = createCriteria(context, Version.class); - criteria.add(Restrictions.eq("versionHistory", versionHistory)); - criteria.add(Restrictions.and(Restrictions.isNotNull("item"))); - criteria.addOrder(Order.desc("versionNumber")); - return list(criteria); + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, Version.class); + Root versionRoot = criteriaQuery.from(Version.class); + criteriaQuery.select(versionRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(versionRoot.get(Version_.versionHistory), versionHistory), + criteriaBuilder.isNotNull(versionRoot.get(Version_.item)) + ) + ); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.desc(versionRoot.get(Version_.versionNumber))); + criteriaQuery.orderBy(orderList); + + return list(context, criteriaQuery, false, Version.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionHistoryDAOImpl.java b/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionHistoryDAOImpl.java index 49e3331b23..eac78c3e62 100644 --- a/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionHistoryDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/versioning/dao/impl/VersionHistoryDAOImpl.java @@ -8,15 +8,20 @@ package org.dspace.versioning.dao.impl; import java.sql.SQLException; +import java.util.LinkedList; +import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; import org.dspace.content.Item; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; +import org.dspace.versioning.Version; import org.dspace.versioning.VersionHistory; +import org.dspace.versioning.Version_; import org.dspace.versioning.dao.VersionHistoryDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the VersionHistory object. @@ -35,10 +40,17 @@ public class VersionHistoryDAOImpl extends AbstractHibernateDAO @Override public VersionHistory findByItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, VersionHistory.class); - criteria.createAlias("versions", "v"); - criteria.add(Restrictions.eq("v.item", item)); - criteria.addOrder(Order.desc("v.versionNumber")); - return singleResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, VersionHistory.class); + Root versionHistoryRoot = criteriaQuery.from(VersionHistory.class); + Join join = versionHistoryRoot.join("versions"); + criteriaQuery.select(versionHistoryRoot); + criteriaQuery.where(criteriaBuilder.equal(join.get(Version_.item), item)); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.desc(join.get(Version_.versionNumber))); + criteriaQuery.orderBy(orderList); + + return singleResult(context, criteriaQuery); } } diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/BasicWorkflowItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/BasicWorkflowItemDAOImpl.java index 358e0923a6..d3ae4ba884 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/BasicWorkflowItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/BasicWorkflowItemDAOImpl.java @@ -8,19 +8,23 @@ package org.dspace.workflowbasic.dao.impl; import java.sql.SQLException; +import java.util.LinkedList; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; import org.dspace.content.Collection; import org.dspace.content.Item; +import org.dspace.content.Item_; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.workflowbasic.BasicWorkflowItem; +import org.dspace.workflowbasic.BasicWorkflowItem_; import org.dspace.workflowbasic.dao.BasicWorkflowItemDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Order; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the BasicWorkflowItem object. @@ -37,27 +41,42 @@ public class BasicWorkflowItemDAOImpl extends AbstractHibernateDAO basicWorkflowItemRoot = criteriaQuery.from(BasicWorkflowItem.class); + criteriaQuery.select(basicWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(basicWorkflowItemRoot.get(BasicWorkflowItem_.item), i)); + return uniqueResult(context, criteriaQuery, false, BasicWorkflowItem.class, -1, -1); } @Override public List findBySubmitter(Context context, EPerson ep) throws SQLException { - Criteria criteria = createCriteria(context, BasicWorkflowItem.class); - criteria.createAlias("item", "i"); - criteria.add(Restrictions.eq("i.submitter", ep)); - criteria.addOrder(Order.asc("workflowitemId")); - return list(criteria); + + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BasicWorkflowItem.class); + Root basicWorkflowItemRoot = criteriaQuery.from(BasicWorkflowItem.class); + Join join = basicWorkflowItemRoot.join("item"); + criteriaQuery.select(basicWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(join.get(Item_.submitter), ep)); + + List orderList = new LinkedList<>(); + orderList.add(criteriaBuilder.asc(basicWorkflowItemRoot.get(BasicWorkflowItem_.workflowitemId))); + criteriaQuery.orderBy(orderList); + + + return list(context, criteriaQuery, false, BasicWorkflowItem.class, -1, -1); } @Override public List findByCollection(Context context, Collection c) throws SQLException { - Criteria criteria = createCriteria(context, BasicWorkflowItem.class); - criteria.add(Restrictions.eq("collection", c)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BasicWorkflowItem.class); + Root basicWorkflowItemRoot = criteriaQuery.from(BasicWorkflowItem.class); + criteriaQuery.select(basicWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(basicWorkflowItemRoot.get(BasicWorkflowItem_.collection), c)); + return list(context, criteriaQuery, false, BasicWorkflowItem.class, -1, -1); } @Override @@ -71,9 +90,12 @@ public class BasicWorkflowItemDAOImpl extends AbstractHibernateDAO findByOwner(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, BasicWorkflowItem.class); - criteria.add(Restrictions.eq("owner", ePerson)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, BasicWorkflowItem.class); + Root basicWorkflowItemRoot = criteriaQuery.from(BasicWorkflowItem.class); + criteriaQuery.select(basicWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(basicWorkflowItemRoot.get(BasicWorkflowItem_.owner), ePerson)); + return list(context, criteriaQuery, false, BasicWorkflowItem.class, -1, -1); } @Override diff --git a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/TaskListItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/TaskListItemDAOImpl.java index 173d09dcc0..ec92faec03 100644 --- a/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/TaskListItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/workflowbasic/dao/impl/TaskListItemDAOImpl.java @@ -9,16 +9,18 @@ package org.dspace.workflowbasic.dao.impl; import java.sql.SQLException; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.workflowbasic.BasicWorkflowItem; import org.dspace.workflowbasic.TaskListItem; +import org.dspace.workflowbasic.TaskListItem_; import org.dspace.workflowbasic.dao.TaskListItemDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the TaskListItem object. @@ -42,8 +44,11 @@ public class TaskListItemDAOImpl extends AbstractHibernateDAO impl @Override public List findByEPerson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, TaskListItem.class); - criteria.add(Restrictions.eq("ePerson", ePerson)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, TaskListItem.class); + Root taskListItemRoot = criteriaQuery.from(TaskListItem.class); + criteriaQuery.select(taskListItemRoot); + criteriaQuery.where(criteriaBuilder.equal(taskListItemRoot.get(TaskListItem_.ePerson), ePerson)); + return list(context, criteriaQuery, false, TaskListItem.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/ClaimedTaskDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/ClaimedTaskDAOImpl.java index 9db89d6317..bb5a167237 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/ClaimedTaskDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/ClaimedTaskDAOImpl.java @@ -9,15 +9,17 @@ package org.dspace.xmlworkflow.storedcomponents.dao.impl; import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.xmlworkflow.storedcomponents.ClaimedTask; +import org.dspace.xmlworkflow.storedcomponents.ClaimedTask_; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.dao.ClaimedTaskDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the ClaimedTask object. @@ -33,79 +35,99 @@ public class ClaimedTaskDAOImpl extends AbstractHibernateDAO implem @Override public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.eq("workflowItem", workflowItem)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem)); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override public ClaimedTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("owner", ePerson) - )); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.owner), ePerson) + ) + ); + return uniqueResult(context, criteriaQuery, false, ClaimedTask.class, -1, -1); + - return uniqueResult(criteria); } @Override public List findByEperson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.eq("owner", ePerson)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.owner), ePerson)); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override public List findByWorkflowItemAndStepId(Context context, XmlWorkflowItem workflowItem, String stepID) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("stepId", stepID) - )); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.stepId), stepID) + ) + ); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override public ClaimedTask findByEPersonAndWorkflowItemAndStepIdAndActionId(Context context, EPerson ePerson, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("owner", ePerson), - Restrictions.eq("stepId", stepID), - Restrictions.eq("actionId", actionID) - )); - - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.stepId), stepID), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.owner), ePerson), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.actionId), actionID) + ) + ); + return uniqueResult(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override public List findByWorkflowItemAndStepIdAndActionId(Context context, XmlWorkflowItem workflowItem, String stepID, String actionID) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("stepId", stepID), - Restrictions.eq("actionId", actionID) - )); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.workflowItem), workflowItem), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.stepId), stepID), + criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.actionId), actionID) + ) + ); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } @Override public List findByStep(Context context, String stepID) throws SQLException { - Criteria criteria = createCriteria(context, ClaimedTask.class); - criteria.add(Restrictions.eq("stepId", stepID)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, ClaimedTask.class); + Root claimedTaskRoot = criteriaQuery.from(ClaimedTask.class); + criteriaQuery.select(claimedTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(claimedTaskRoot.get(ClaimedTask_.stepId), stepID)); + return list(context, criteriaQuery, false, ClaimedTask.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/CollectionRoleDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/CollectionRoleDAOImpl.java index db83d472e5..c4218d7109 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/CollectionRoleDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/CollectionRoleDAOImpl.java @@ -9,15 +9,17 @@ package org.dspace.xmlworkflow.storedcomponents.dao.impl; import java.sql.SQLException; import java.util.List; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.content.Collection; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.xmlworkflow.storedcomponents.CollectionRole; +import org.dspace.xmlworkflow.storedcomponents.CollectionRole_; import org.dspace.xmlworkflow.storedcomponents.dao.CollectionRoleDAO; -import org.hibernate.Criteria; -import org.hibernate.Query; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the CollectionRole object. @@ -33,23 +35,27 @@ public class CollectionRoleDAOImpl extends AbstractHibernateDAO @Override public List findByCollection(Context context, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, CollectionRole.class); - criteria.add(Restrictions.eq("collection", collection)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, CollectionRole.class); + Root collectionRoleRoot = criteriaQuery.from(CollectionRole.class); + criteriaQuery.select(collectionRoleRoot); + criteriaQuery.where(criteriaBuilder.equal(collectionRoleRoot.get(CollectionRole_.collection), collection)); + return list(context, criteriaQuery, false, CollectionRole.class, -1, -1); } @Override public CollectionRole findByCollectionAndRole(Context context, Collection collection, String role) throws SQLException { - Criteria criteria = createCriteria(context, CollectionRole.class); - criteria.add(Restrictions.and( - Restrictions.eq("collection", collection), - Restrictions.eq("roleId", role) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, CollectionRole.class); + Root collectionRoleRoot = criteriaQuery.from(CollectionRole.class); + criteriaQuery.select(collectionRoleRoot); + criteriaQuery.where( + criteriaBuilder.and(criteriaBuilder.equal(collectionRoleRoot.get(CollectionRole_.collection), collection), + criteriaBuilder.equal(collectionRoleRoot.get(CollectionRole_.roleId), role) + ) ); - - return uniqueResult(criteria); + return uniqueResult(context, criteriaQuery, false, CollectionRole.class, -1, -1); } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/InProgressUserDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/InProgressUserDAOImpl.java index 60e9316c6b..cdba1600a8 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/InProgressUserDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/InProgressUserDAOImpl.java @@ -9,15 +9,17 @@ package org.dspace.xmlworkflow.storedcomponents.dao.impl; import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.xmlworkflow.storedcomponents.InProgressUser; +import org.dspace.xmlworkflow.storedcomponents.InProgressUser_; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.dao.InProgressUserDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the InProgressUser object. @@ -34,54 +36,70 @@ public class InProgressUserDAOImpl extends AbstractHibernateDAO @Override public InProgressUser findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("ePerson", ePerson) - ) + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, InProgressUser.class); + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + criteriaQuery.select(inProgressUserRoot); + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.workflowItem), workflowItem), + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.ePerson), ePerson) + ) ); - return uniqueResult(criteria); + return uniqueResult(context, criteriaQuery, false, InProgressUser.class, -1, -1); + } @Override public List findByEperson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add(Restrictions.eq("ePerson", ePerson)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, InProgressUser.class); + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + criteriaQuery.select(inProgressUserRoot); + criteriaQuery.where(criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.ePerson), ePerson)); + return list(context, criteriaQuery, false, InProgressUser.class, -1, -1); } @Override public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add(Restrictions.eq("workflowItem", workflowItem)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, InProgressUser.class); + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + criteriaQuery.select(inProgressUserRoot); + criteriaQuery.where(criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.workflowItem), workflowItem)); + return list(context, criteriaQuery, false, InProgressUser.class, -1, -1); } @Override public int countInProgressUsers(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("finished", false) - ) - ); - return count(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.workflowItem), workflowItem), + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.finished), false) + ) + ); + return count(context, criteriaQuery, criteriaBuilder, inProgressUserRoot); } @Override public int countFinishedUsers(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, InProgressUser.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("finished", true) - ) + + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root inProgressUserRoot = criteriaQuery.from(InProgressUser.class); + + criteriaQuery.where(criteriaBuilder.and( + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.workflowItem), workflowItem), + criteriaBuilder.equal(inProgressUserRoot.get(InProgressUser_.finished), true) + ) ); - return count(criteria); + return count(context, criteriaQuery, criteriaBuilder, inProgressUserRoot); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/PoolTaskDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/PoolTaskDAOImpl.java index ea20e79db5..b38041da39 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/PoolTaskDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/PoolTaskDAOImpl.java @@ -9,16 +9,18 @@ package org.dspace.xmlworkflow.storedcomponents.dao.impl; import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.eperson.Group; import org.dspace.xmlworkflow.storedcomponents.PoolTask; +import org.dspace.xmlworkflow.storedcomponents.PoolTask_; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.dao.PoolTaskDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the PoolTask object. @@ -34,53 +36,62 @@ public class PoolTaskDAOImpl extends AbstractHibernateDAO implements P @Override public List findByEPerson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add(Restrictions.eq("ePerson", ePerson)); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.ePerson), ePerson)); + return list(context, criteriaQuery, false, PoolTask.class, -1, -1); - return list(criteria); } @Override public List findByGroup(Context context, Group group) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add(Restrictions.eq("group", group)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.group), group)); + return list(context, criteriaQuery, false, PoolTask.class, -1, -1); } @Override public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add(Restrictions.eq("workflowItem", workflowItem)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery.where(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.workflowItem), workflowItem)); + return list(context, criteriaQuery, false, PoolTask.class, -1, -1); } @Override public PoolTask findByWorkflowItemAndEPerson(Context context, XmlWorkflowItem workflowItem, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("ePerson", ePerson) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.workflowItem), workflowItem), + criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.ePerson), ePerson) + ) ); - - return uniqueResult(criteria); + return uniqueResult(context, criteriaQuery, false, PoolTask.class, -1, -1); } @Override public PoolTask findByWorkflowItemAndGroup(Context context, Group group, XmlWorkflowItem workflowItem) throws SQLException { - Criteria criteria = createCriteria(context, PoolTask.class); - criteria.add( - Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("group", group) - ) + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, PoolTask.class); + Root poolTaskRoot = criteriaQuery.from(PoolTask.class); + criteriaQuery.select(poolTaskRoot); + criteriaQuery + .where(criteriaBuilder.and(criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.workflowItem), workflowItem), + criteriaBuilder.equal(poolTaskRoot.get(PoolTask_.group), group) + ) ); - - return uniqueResult(criteria); + return uniqueResult(context, criteriaQuery, false, PoolTask.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/WorkflowItemRoleDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/WorkflowItemRoleDAOImpl.java index dfc75fd069..fdc2413b5f 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/WorkflowItemRoleDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/WorkflowItemRoleDAOImpl.java @@ -9,15 +9,17 @@ package org.dspace.xmlworkflow.storedcomponents.dao.impl; import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole; +import org.dspace.xmlworkflow.storedcomponents.WorkflowItemRole_; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; import org.dspace.xmlworkflow.storedcomponents.dao.WorkflowItemRoleDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the WorkflowItemRole object. @@ -27,37 +29,49 @@ import org.hibernate.criterion.Restrictions; * @author kevinvandevelde at atmire.com */ public class WorkflowItemRoleDAOImpl extends AbstractHibernateDAO implements WorkflowItemRoleDAO { + protected WorkflowItemRoleDAOImpl() { super(); } @Override - public List findByWorkflowItemAndRole(Context context, XmlWorkflowItem workflowItem, String role) - throws SQLException { - Criteria criteria = createCriteria(context, WorkflowItemRole.class); - criteria.add(Restrictions.and( - Restrictions.eq("workflowItem", workflowItem), - Restrictions.eq("role", role) - ) + public List findByWorkflowItemAndRole(Context context, + XmlWorkflowItem workflowItem, + String role) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkflowItemRole.class); + Root workflowItemRoleRoot = criteriaQuery.from(WorkflowItemRole.class); + criteriaQuery.select(workflowItemRoleRoot); + criteriaQuery.where(criteriaBuilder.and(criteriaBuilder + .equal(workflowItemRoleRoot.get(WorkflowItemRole_.workflowItem), + workflowItem), + criteriaBuilder + .equal(workflowItemRoleRoot.get(WorkflowItemRole_.roleId), + role) + ) ); - - return list(criteria); + return list(context, criteriaQuery, false, WorkflowItemRole.class, -1, -1); } @Override - public List findByWorkflowItem(Context context, XmlWorkflowItem workflowItem) - throws SQLException { - Criteria criteria = createCriteria(context, WorkflowItemRole.class); - criteria.add(Restrictions.eq("workflowItem", workflowItem)); - - return list(criteria); + public List findByWorkflowItem(Context context, + XmlWorkflowItem workflowItem) throws SQLException { + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkflowItemRole.class); + Root workflowItemRoleRoot = criteriaQuery.from(WorkflowItemRole.class); + criteriaQuery.select(workflowItemRoleRoot); + criteriaQuery.where(criteriaBuilder.equal(workflowItemRoleRoot.get(WorkflowItemRole_.workflowItem), + workflowItem)); + return list(context, criteriaQuery, false, WorkflowItemRole.class, -1, -1); } @Override public List findByEPerson(Context context, EPerson ePerson) throws SQLException { - Criteria criteria = createCriteria(context, WorkflowItemRole.class); - criteria.add(Restrictions.eq("ePerson", ePerson)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, WorkflowItemRole.class); + Root workflowItemRoleRoot = criteriaQuery.from(WorkflowItemRole.class); + criteriaQuery.select(workflowItemRoleRoot); + criteriaQuery.where(criteriaBuilder.equal(workflowItemRoleRoot.get(WorkflowItemRole_.ePerson), ePerson)); + return list(context, criteriaQuery, false, WorkflowItemRole.class, -1, -1); } } diff --git a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/XmlWorkflowItemDAOImpl.java b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/XmlWorkflowItemDAOImpl.java index f32e3d9db7..3c14e42a5b 100644 --- a/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/XmlWorkflowItemDAOImpl.java +++ b/dspace-api/src/main/java/org/dspace/xmlworkflow/storedcomponents/dao/impl/XmlWorkflowItemDAOImpl.java @@ -10,15 +10,20 @@ package org.dspace.xmlworkflow.storedcomponents.dao.impl; import java.sql.SQLException; import java.util.List; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Root; + import org.dspace.content.Collection; import org.dspace.content.Item; +import org.dspace.content.Item_; import org.dspace.core.AbstractHibernateDAO; import org.dspace.core.Context; import org.dspace.eperson.EPerson; import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem; +import org.dspace.xmlworkflow.storedcomponents.XmlWorkflowItem_; import org.dspace.xmlworkflow.storedcomponents.dao.XmlWorkflowItemDAO; -import org.hibernate.Criteria; -import org.hibernate.criterion.Restrictions; /** * Hibernate implementation of the Database Access Object interface class for the XmlWorkflowItem object. @@ -34,21 +39,24 @@ public class XmlWorkflowItemDAOImpl extends AbstractHibernateDAO findAllInCollection(Context context, Integer offset, Integer limit, + public List findAllInCollection(Context context, Integer offset, + Integer limit, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, XmlWorkflowItem.class); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, XmlWorkflowItem.class); + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); + criteriaQuery.select(xmlWorkflowItemRoot); if (collection != null) { - criteria.add(Restrictions.eq("collection", collection)); + criteriaQuery.where(criteriaBuilder.equal(xmlWorkflowItemRoot.get(XmlWorkflowItem_.collection), + collection)); } - - if (offset != null) { - criteria.setFirstResult(offset); + if (offset == null) { + offset = -1; } - if (limit != null) { - criteria.setMaxResults(limit); + if (limit == null) { + limit = -1; } - - return list(criteria); + return list(context, criteriaQuery, false, XmlWorkflowItem.class, limit, offset); } @Override @@ -58,35 +66,48 @@ public class XmlWorkflowItemDAOImpl extends AbstractHibernateDAO criteriaQuery = criteriaBuilder.createQuery(Long.class); + + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); if (collection != null) { - criteria.add(Restrictions.eq("collection", collection)); + criteriaQuery.where(criteriaBuilder.equal(xmlWorkflowItemRoot.get(XmlWorkflowItem_.collection), + collection)); } - return count(criteria); + return count(context, criteriaQuery, criteriaBuilder, xmlWorkflowItemRoot); } @Override public List findBySubmitter(Context context, EPerson ep) throws SQLException { - Criteria criteria = createCriteria(context, XmlWorkflowItem.class); - criteria.createAlias("item", "i"); - criteria.add(Restrictions.eq("i.submitter", ep)); - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, XmlWorkflowItem.class); + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); + Join join = xmlWorkflowItemRoot.join("item"); + criteriaQuery.select(xmlWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(join.get(Item_.submitter), ep)); + return list(context, criteriaQuery, false, XmlWorkflowItem.class, -1, -1); } @Override public List findByCollection(Context context, Collection collection) throws SQLException { - Criteria criteria = createCriteria(context, XmlWorkflowItem.class); - criteria.add(Restrictions.eq("collection", collection)); - - return list(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, XmlWorkflowItem.class); + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); + criteriaQuery.select(xmlWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(xmlWorkflowItemRoot.get(XmlWorkflowItem_.collection), collection)); + return list(context, criteriaQuery, false, XmlWorkflowItem.class, -1, -1); } @Override public XmlWorkflowItem findByItem(Context context, Item item) throws SQLException { - Criteria criteria = createCriteria(context, XmlWorkflowItem.class); - criteria.add(Restrictions.eq("item", item)); - - return uniqueResult(criteria); + CriteriaBuilder criteriaBuilder = getCriteriaBuilder(context); + CriteriaQuery criteriaQuery = getCriteriaQuery(criteriaBuilder, XmlWorkflowItem.class); + Root xmlWorkflowItemRoot = criteriaQuery.from(XmlWorkflowItem.class); + criteriaQuery.select(xmlWorkflowItemRoot); + criteriaQuery.where(criteriaBuilder.equal(xmlWorkflowItemRoot.get(XmlWorkflowItem_.item), item)); + return uniqueResult(context, criteriaQuery, false, XmlWorkflowItem.class, -1, -1); } } diff --git a/dspace-api/src/test/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImplTest.java b/dspace-api/src/test/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImplTest.java index 952e091db8..2e33d96d73 100644 --- a/dspace-api/src/test/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImplTest.java +++ b/dspace-api/src/test/java/org/dspace/checker/dao/impl/ChecksumHistoryDAOImplTest.java @@ -15,6 +15,7 @@ import java.sql.SQLException; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import javax.persistence.Query; import org.dspace.AbstractUnitTest; import org.dspace.checker.ChecksumResultCode; @@ -23,7 +24,6 @@ import org.dspace.content.factory.ContentServiceFactory; import org.dspace.content.service.BitstreamService; import org.dspace.core.CoreHelpers; import org.dspace.core.HibernateDBConnection; -import org.hibernate.Query; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; @@ -87,9 +87,9 @@ public class ChecksumHistoryDAOImplTest cal.add(Calendar.DATE, -1); Date matchDate = cal.getTime(); checkId++; - qry.setInteger("id", checkId); - qry.setDate("date", matchDate); - qry.setString("result", ChecksumResultCode.CHECKSUM_MATCH.name()); + qry.setParameter("id", checkId); + qry.setParameter("date", matchDate); + qry.setParameter("result", ChecksumResultCode.CHECKSUM_MATCH.name()); qry.setParameter("bitstream", bs.getID()); // FIXME identifier not being set??? qry.executeUpdate(); @@ -97,9 +97,9 @@ public class ChecksumHistoryDAOImplTest cal.add(Calendar.DATE, -1); Date noMatchDate = cal.getTime(); checkId++; - qry.setInteger("id", checkId); - qry.setDate("date", noMatchDate); - qry.setString("result", ChecksumResultCode.CHECKSUM_NO_MATCH.name()); + qry.setParameter("id", checkId); + qry.setParameter("date", noMatchDate); + qry.setParameter("result", ChecksumResultCode.CHECKSUM_NO_MATCH.name()); qry.setParameter("bitstream", bs.getID()); // FIXME identifier not being set??? qry.executeUpdate(); @@ -107,9 +107,9 @@ public class ChecksumHistoryDAOImplTest cal.add(Calendar.DATE, +3); Date futureDate = cal.getTime(); checkId++; - qry.setInteger("id", checkId); - qry.setDate("date", new java.sql.Date(futureDate.getTime())); - qry.setString("result", ChecksumResultCode.CHECKSUM_MATCH.name()); + qry.setParameter("id", checkId); + qry.setParameter("date", new java.sql.Date(futureDate.getTime())); + qry.setParameter("result", ChecksumResultCode.CHECKSUM_MATCH.name()); qry.setParameter("bitstream", bs.getID()); // FIXME identifier not being set??? qry.executeUpdate(); @@ -125,18 +125,18 @@ public class ChecksumHistoryDAOImplTest "SELECT COUNT(*) FROM ChecksumHistory WHERE process_end_date = :date"); long count; - qry.setDate("date", matchDate); - count = (Long) qry.uniqueResult(); + qry.setParameter("date", matchDate); + count = (Long) qry.getSingleResult(); assertEquals("Should find no row at matchDate", count, 0); // See if nonmatching old row is still present. - qry.setDate("date", noMatchDate); - count = (Long) qry.uniqueResult(); + qry.setParameter("date", noMatchDate); + count = (Long) qry.getSingleResult(); assertEquals("Should find one row at noMatchDate", count, 1); // See if new row is still present. - qry.setDate("date", futureDate); - count = (Long) qry.uniqueResult(); + qry.setParameter("date", futureDate); + count = (Long) qry.getSingleResult(); assertEquals("Should find one row at futureDate", count, 1); } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/BitstreamContentRestController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/BitstreamContentRestController.java index c09cebfde6..e60007d8ab 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/BitstreamContentRestController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/BitstreamContentRestController.java @@ -27,6 +27,7 @@ import org.dspace.content.BitstreamFormat; import org.dspace.content.service.BitstreamService; import org.dspace.core.Context; import org.dspace.disseminate.service.CitationDocumentService; +import org.dspace.services.ConfigurationService; import org.dspace.services.EventService; import org.dspace.usage.UsageEvent; import org.springframework.beans.factory.annotation.Autowired; @@ -70,6 +71,9 @@ public class BitstreamContentRestController { @Autowired private CitationDocumentService citationDocumentService; + @Autowired + private ConfigurationService configurationService; + @PreAuthorize("hasPermission(#uuid, 'BITSTREAM', 'READ')") @RequestMapping(method = {RequestMethod.GET, RequestMethod.HEAD}) public void retrieve(@PathVariable UUID uuid, HttpServletResponse response, @@ -104,6 +108,12 @@ public class BitstreamContentRestController { .with(request) .with(response); + //Determine if we need to send the file as a download or if the browser can open it inline + long dispositionThreshold = configurationService.getLongProperty("webui.content_disposition_threshold"); + if (dispositionThreshold >= 0 && bitstreamTuple.getRight() > dispositionThreshold) { + sender.withDisposition(MultipartFileSender.CONTENT_DISPOSITION_ATTACHMENT); + } + if (sender.isNoRangeRequest() && isNotAnErrorResponse(response)) { //We only log a download request when serving a request without Range header. This is because //a browser always sends a regular request first to check for Range support. diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java index bfd5296e22..bb9964e20b 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/RestResourceController.java @@ -10,18 +10,22 @@ package org.dspace.app.rest; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.methodOn; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.UUID; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; + import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; @@ -46,6 +50,7 @@ import org.dspace.app.rest.repository.DSpaceRestRepository; import org.dspace.app.rest.repository.LinkRestRepository; import org.dspace.app.rest.utils.RestRepositoryUtils; import org.dspace.app.rest.utils.Utils; +import org.dspace.authorize.AuthorizeException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; @@ -60,6 +65,7 @@ import org.springframework.hateoas.Link; import org.springframework.hateoas.PagedResources; import org.springframework.hateoas.Resource; import org.springframework.hateoas.ResourceSupport; +import org.springframework.hateoas.Resources; import org.springframework.hateoas.UriTemplate; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -426,17 +432,23 @@ public class RestResourceController implements InitializingBean { } /** - * Called in POST, multipart, upload a resource passed into "file" request parameter + * Called in POST, multipart, upload to a specific rest resource the file passed as "file" request parameter * * Note that the regular expression in the request mapping accept a number as identifier; * * @param request + * the http request * @param apiCategory + * the api category * @param model + * the rest model that identify the REST resource collection * @param id + * the id of the specific rest resource * @param extraField + * the original name of the uploaded file * @param uploadfile - * @return + * the file to upload + * @return the created resource * @throws HttpRequestMethodNotSupportedException */ @RequestMapping(method = RequestMethod.POST, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_DIGIT, headers = @@ -454,17 +466,23 @@ public class RestResourceController implements InitializingBean { } /** - * Called in POST, multipart, upload a resource passed into "file" request parameter + * Called in POST, multipart, upload to a specific rest resource the file passed as "file" request parameter * * Note that the regular expression in the request mapping accept a UUID as identifier; * * @param request + * the http request * @param apiCategory + * the api category * @param model + * the rest model that identify the REST resource collection * @param id + * the id of the specific rest resource * @param extraField + * the original name of the uploaded file * @param uploadfile - * @return + * the file to upload + * @return the created resource * @throws HttpRequestMethodNotSupportedException */ @RequestMapping(method = RequestMethod.POST, value = REGEX_REQUESTMAPPING_IDENTIFIER_AS_UUID, headers = @@ -512,6 +530,48 @@ public class RestResourceController implements InitializingBean { return ControllerUtils.toResponseEntity(HttpStatus.CREATED, null, result); } + /** + * Upload a file against the collection resource endpoint. This is typically used for bulk creation of resources + * such for instance multiple workspaceitems from a CSV or bibliographic file + * + * @param request + * the http request + * @param apiCategory + * the api category + * @param model + * the rest model that identify the REST resource collection + * @param uploadfile + * the bulk file + * @return the list of generated resources + * @throws SQLException + * @throws FileNotFoundException + * @throws IOException + * @throws AuthorizeException + */ + @RequestMapping(method = { RequestMethod.POST }, headers = "content-type=multipart/form-data") + public ResponseEntity upload(HttpServletRequest request, + @PathVariable String apiCategory, + @PathVariable String model, + @RequestParam(required = false) + String extraField, + @RequestParam("file") MultipartFile + uploadfile) + throws SQLException, FileNotFoundException, IOException, AuthorizeException { + + checkModelPluralForm(apiCategory, model); + DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); + + Iterable content = repository.upload(request, extraField, uploadfile); + + List resources = new ArrayList<>(); + for (T modelObject : content) { + DSpaceResource result = repository.wrapResource(modelObject); + linkService.addLinks(result); + resources.add(result); + } + return ControllerUtils.toResponseEntity(HttpStatus.OK, null, Resources.wrap(resources)); + } + /** * PATCH method, using operation on the resources following (JSON) Patch notation (https://tools.ietf * .org/html/rfc6902) @@ -573,7 +633,6 @@ public class RestResourceController implements InitializingBean { String model, ID id, JsonNode jsonNode) throws HttpRequestMethodNotSupportedException { - checkModelPluralForm(apiCategory, model); DSpaceRestRepository repository = utils.getResourceRepository(apiCategory, model); RestAddressableModel modelObject = null; diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java index f148d4cc64..45470c3e8e 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/DiscoverResultConverter.java @@ -12,7 +12,7 @@ import java.util.Map; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.dspace.app.rest.converter.query.SearchQueryConverter; import org.dspace.app.rest.model.DSpaceObjectRest; diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/WorkspaceItemConverter.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/WorkspaceItemConverter.java index 4b8bcd9700..89eae193dc 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/WorkspaceItemConverter.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/converter/WorkspaceItemConverter.java @@ -85,6 +85,10 @@ public class WorkspaceItemConverter // info if (collection != null) { + // we set the status to true as we will discover validation error later in this block + // we could eventually leave the status to empty if we don't have collection information, this could be + // eventually the case when projection support will be included + witem.setStatus(true); SubmissionDefinitionRest def = submissionDefinitionConverter .convert(submissionConfigReader.getSubmissionConfigByCollection(collection.getHandle())); witem.setSubmissionDefinition(def); @@ -108,6 +112,7 @@ public class WorkspaceItemConverter (AbstractRestProcessingStep) stepClass.newInstance(); for (ErrorRest error : stepProcessing.validate(submissionService, obj, stepConfig)) { addError(witem.getErrors(), error); + witem.setStatus(false); } witem.getSections() .put(sections.getId(), stepProcessing.getData(submissionService, obj, stepConfig)); diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/ErrorRest.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/ErrorRest.java index 054ea022dd..59bf9176dd 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/ErrorRest.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/model/ErrorRest.java @@ -21,6 +21,11 @@ public class ErrorRest { private List paths; + /** + * The error message as i18key + * + * @return The message as i18key + */ public String getMessage() { return message; } @@ -29,6 +34,13 @@ public class ErrorRest { this.message = message; } + /** + * The json paths where the error message apply. They can be as detailed as a specific value in a multivalues + * attributes (i.e. sections.traditionalpageone['dc.contributor.author'][1] to identify the second author - 0 based) + * or generic to apply to a whole section (sections.license) + * + * @return + */ public List getPaths() { if (this.paths == null) { this.paths = new ArrayList(); diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java index 050f547296..181af6b2e1 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/DSpaceRestRepository.java @@ -68,48 +68,94 @@ public abstract class DSpaceRestRepository S save(Context context, S entity) throws AuthorizeException, RepositoryMethodNotImplementedException { throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", ""); } @Override + /** + * Method to implement to support bulk update of a REST objects via a PUT request + */ public Iterable save(Iterable entities) { // TODO Auto-generated method stub return null; } @Override + /** + * Return a specific REST object + * + * @return the REST object identified by its ID + */ public T findOne(ID id) { Context context = obtainContext(); return thisRepository.findOne(context, id); } + /** + * Method to implement to support retrieval of a specific REST object instance + * + * @param context + * the dspace context + * @param id + * the rest object id + * @return the REST object identified by its ID + */ public abstract T findOne(Context context, ID id); @Override + /** + * Return true if an object exist for the specified ID. The default implementation is inefficient as it retrieves + * the actual object to state that it exists. This could lead to retrieve and inizialize lot of linked objects + */ public boolean exists(ID id) { - // TODO Auto-generated method stub - return false; + return findOne(id) != null; } @Override - public Iterable findAll() { + /** + * This method cannot be implemented we required all the find method to be paginated + */ + public final Iterable findAll() { throw new RuntimeException("findAll MUST be paginated"); } @Override + /** + * This method could be implemented to support bulk retrieval of specific object by their IDs. Unfortunately, this + * method doesn't allow pagination and it could be misused to retrieve thousand objects at once + */ public Iterable findAll(Iterable ids) { throw new RuntimeException("findAll MUST be paginated"); } @Override + /** + * This method return the number of object instances of the type managed by the repository class available in the + * system + */ public long count() { - // TODO Auto-generated method stub + // FIXME DS-4038 return 0; } @Override + /** + * Delete the object identified by its ID + */ public void delete(ID id) { Context context = obtainContext(); try { @@ -122,44 +168,96 @@ public abstract class DSpaceRestRepository entities) { // TODO Auto-generated method stub } @Override + /** + * Method to implement to support bulk delete of ALL entity instances + */ public void deleteAll() { // TODO Auto-generated method stub } @Override - public Iterable findAll(Sort sort) { + /** + * This method cannot be implemented we required all the find method to be paginated + */ + public final Iterable findAll(Sort sort) { throw new RuntimeException("findAll MUST be paginated"); } @Override + /** + * Provide access to the manage entity instances in a paginated way + */ public Page findAll(Pageable pageable) { Context context = obtainContext(); return thisRepository.findAll(context, pageable); } + /** + * Method to implement to support scroll of entity instances from the collection resource endpoin + * + * @param context + * the dspace context + * @param pageable + * object embedding the requested pagination info + * @return + */ public abstract Page findAll(Context context, Pageable pageable); + /** + * The REST model supported by the repository + */ public abstract Class getDomainClass(); + /** + * Wrap the REST model in a REST HAL Resource + * + * @param model + * the rest model instance + * @param rels + * the HAL links + * @return the REST Resource + */ public abstract DSpaceResource wrapResource(T model, String... rels); + /** + * Create and return a new instance. Data are usually retrieved from the thread bound http request + * + * @return the created REST object + */ public T createAndReturn() { Context context = null; try { @@ -174,16 +272,60 @@ public abstract class DSpaceRestRepository upload(HttpServletRequest request, MultipartFile uploadfile) + /** + * Bulk create object instances from an uploaded file + * + * @param request + * the http request + * @param extraField + * the original name of the uploaded file + * @param uploadfile + * the file to process + * @return the created objects + * @throws SQLException + * @throws FileNotFoundException + * @throws IOException + * @throws AuthorizeException + */ + public Iterable upload(HttpServletRequest request, String extraField, MultipartFile uploadfile) throws SQLException, FileNotFoundException, IOException, AuthorizeException { Context context = obtainContext(); - Iterable entity = upload(context, request, uploadfile); + Iterable entity = upload(context, request, extraField, uploadfile); context.commit(); return entity; } - protected Iterable upload(Context context, HttpServletRequest request, MultipartFile uploadfile) + /** + * Method to implement to support bulk creation of objects from a file + * + * @param request + * the http request + * @param extraField + * the original name of the uploaded file + * @param uploadfile + * the file to process + * @return the created objects + * @throws SQLException + * @throws FileNotFoundException + * @throws IOException + * @throws AuthorizeException + * @throws RepositoryMethodNotImplementedException + */ + protected Iterable upload(Context context, HttpServletRequest request, String extraField, + MultipartFile uploadfile) throws SQLException, FileNotFoundException, IOException, AuthorizeException { - throw new RuntimeException("No implementation found; Method not allowed!"); + throw new RepositoryMethodNotImplementedException("No implementation found; Method not allowed!", ""); } } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java index 3bff819652..98ce42b614 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/repository/WorkspaceItemRestRepository.java @@ -65,6 +65,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; +import org.springframework.data.rest.webmvc.json.patch.PatchException; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; @@ -325,6 +326,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository upload(Context context, HttpServletRequest request, MultipartFile uploadfile) + public Iterable upload(Context context, HttpServletRequest request, String extraField, + MultipartFile uploadfile) throws SQLException, FileNotFoundException, IOException, AuthorizeException { File file = Utils.getFile(uploadfile, "upload-loader", "filedataloader"); List results = new ArrayList<>(); @@ -360,7 +363,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository tmpResult = new ArrayList(); TransformationEngine transformationEngine1 = submissionLookupService.getPhase1TransformationEngine(); + TransformationSpec spec = new TransformationSpec(); + // FIXME this is mostly due to the need to test. The BTE framework has an assert statement that check if the + // number of found record is less than the requested and treat 0 as is, instead, the implementation assume + // 0=unlimited this lead to test failure. + // It is unclear if BTE really respect values other than 0/MAX allowing us to put a protection against heavy + // load + spec.setNumberOfRecords(Integer.MAX_VALUE); if (transformationEngine1 != null) { MultipleSubmissionLookupDataLoader dataLoader = (MultipleSubmissionLookupDataLoader) transformationEngine1.getDataLoader(); @@ -383,7 +393,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository()); log.debug("BTE transformation is about to start!"); - transformationEngine1.transform(new TransformationSpec()); + transformationEngine1.transform(spec); log.debug("BTE transformation finished!"); tmpResult.addAll(outputGenerator.getDtoList()); if (!tmpResult.isEmpty()) { @@ -417,7 +427,7 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository T getData(SubmissionService submissionService, WorkspaceItem obj, SubmissionStepConfig config) throws Exception; + /** + * The method will expose the list of validation errors identified by the step. The default implementation will + * found a {@link Validation} spring bean in the context with the same name that the step id + * + * @param submissionService + * @param obj + * @param config + * @return + * @throws Exception + */ default public List validate(SubmissionService submissionService, WorkspaceItem obj, SubmissionStepConfig config) throws Exception { List errors = new ArrayList(); @@ -55,6 +80,19 @@ public interface AbstractRestProcessingStep extends ListenerProcessingStep { return errors; } + /** + * Method to react to a patch request against the step managed section data + * + * @param context + * the DSpace context + * @param currentRequest + * the http request + * @param source + * the in progress submission + * @param op + * the json patch operation + * @throws Exception + */ public void doPatchProcessing(Context context, Request currentRequest, WorkspaceItem source, Operation op) throws Exception; diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/ListenerProcessingStep.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/ListenerProcessingStep.java index 72bcc35da8..f2e3513fab 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/ListenerProcessingStep.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/ListenerProcessingStep.java @@ -11,7 +11,13 @@ import org.dspace.content.InProgressSubmission; import org.dspace.core.Context; /** + * This interface allows a submission step to access and modify if needed an inprogress submission also when changes are + * requested to sections other than the one managed by the step itself. + * + * This could be useful to allow a step wide validations or changes over multiple sections. + * * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + * @author Andrea Bollini (andrea.bollini at 4science.it) */ public interface ListenerProcessingStep { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/SubmissionService.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/SubmissionService.java index 19ac5cddee..949dad270c 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/SubmissionService.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/SubmissionService.java @@ -18,12 +18,14 @@ import org.apache.log4j.Logger; import org.atteo.evo.inflector.English; import org.dspace.app.rest.converter.BitstreamFormatConverter; import org.dspace.app.rest.converter.ResourcePolicyConverter; +import org.dspace.app.rest.exception.RESTAuthorizationException; import org.dspace.app.rest.model.BitstreamRest; import org.dspace.app.rest.model.CheckSumRest; import org.dspace.app.rest.model.MetadataValueRest; import org.dspace.app.rest.model.ResourcePolicyRest; import org.dspace.app.rest.model.step.UploadBitstreamRest; import org.dspace.app.rest.utils.ContextUtil; +import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.ResourcePolicy; import org.dspace.content.Bitstream; import org.dspace.content.Collection; @@ -31,12 +33,14 @@ import org.dspace.content.MetadataValue; import org.dspace.content.WorkspaceItem; import org.dspace.content.service.CollectionService; import org.dspace.content.service.WorkspaceItemService; +import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.Utils; import org.dspace.services.ConfigurationService; import org.dspace.services.RequestService; import org.dspace.services.model.Request; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.datasource.init.UncategorizedScriptException; import org.springframework.stereotype.Component; /** @@ -64,23 +68,35 @@ public class SubmissionService { public WorkspaceItem createWorkspaceItem(Context context, Request request) { WorkspaceItem wsi = null; + Collection collection = null; String collectionUUID = request.getHttpServletRequest().getParameter("collection"); + if (StringUtils.isBlank(collectionUUID)) { - String uuid = configurationService.getProperty("submission.default.collection"); - Collection collection = null; - try { - if (StringUtils.isNotBlank(uuid)) { - collection = collectionService.find(context, UUID.fromString(uuid)); + collectionUUID = configurationService.getProperty("submission.default.collection"); + } + + try { + if (StringUtils.isNotBlank(collectionUUID)) { + collection = collectionService.find(context, UUID.fromString(collectionUUID)); + } else { + final List findAuthorizedOptimized = collectionService.findAuthorizedOptimized(context, + Constants.ADD); + if (findAuthorizedOptimized != null && findAuthorizedOptimized.size() > 0) { + collection = findAuthorizedOptimized.get(0); } else { - collection = collectionService.findAll(context, 1, 0).get(0); + throw new RESTAuthorizationException("No collection suitable for submission for the current user"); } - wsi = workspaceItemService.create(context, collection, true); - } catch (Exception e) { - log.error(e.getMessage(), e); } - } else { - //TODO manage setup of default collection in the case WSI it is not null - //TODO manage setup of collection discovered into request + + if (collection == null) { + throw new RESTAuthorizationException("collectionUUID=" + collectionUUID + " not found"); + } + wsi = workspaceItemService.create(context, collection, true); + } catch (SQLException e) { + // wrap in a runtime exception as we cannot change the method signature + throw new UncategorizedScriptException(e.getMessage(), e); + } catch (AuthorizeException ae) { + throw new RESTAuthorizationException(ae); } return wsi; } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/UploadableStep.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/UploadableStep.java index e416b4cddd..df7c54f249 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/UploadableStep.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/UploadableStep.java @@ -16,7 +16,10 @@ import org.dspace.core.Context; import org.springframework.web.multipart.MultipartFile; /** + * The interface for submission Steps that need to deal with file upload + * * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + * @author Andrea Bollini (andrea.bollini at 4science.it) */ public interface UploadableStep extends ListenerProcessingStep { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseAddPatchOperation.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseAddPatchOperation.java index 6038660586..044b27ac3b 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseAddPatchOperation.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseAddPatchOperation.java @@ -52,7 +52,13 @@ public class LicenseAddPatchOperation extends AddPatchOperation { void add(Context context, Request currentRequest, WorkspaceItem source, String path, Object value) throws Exception { - Boolean grant = BooleanUtils.toBooleanObject((String) value); + Boolean grant = null; + // we are friendly with the client and accept also a string representation for the boolean + if (value instanceof String) { + grant = BooleanUtils.toBooleanObject((String) value); + } else { + grant = (Boolean) value; + } if (grant == null) { throw new IllegalArgumentException( diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseReplacePatchOperation.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseReplacePatchOperation.java index 30c7558cee..0efa7d0b02 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseReplacePatchOperation.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/factory/impl/LicenseReplacePatchOperation.java @@ -33,7 +33,13 @@ public class LicenseReplacePatchOperation extends ReplacePatchOperation void replace(Context context, Request currentRequest, WorkspaceItem source, String path, Object value) throws Exception { - Boolean grant = BooleanUtils.toBooleanObject((String) value); + Boolean grant = null; + // we are friendly with the client and accept also a string representation for the boolean + if (value instanceof String) { + grant = BooleanUtils.toBooleanObject((String) value); + } else { + grant = (Boolean) value; + } if (grant == null) { throw new IllegalArgumentException( diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/DescribeStep.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/DescribeStep.java index 313d6b64d9..0a66abbc00 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/DescribeStep.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/DescribeStep.java @@ -31,9 +31,11 @@ import org.dspace.core.Utils; import org.dspace.services.model.Request; /** - * Describe step for DSpace Spring Rest. Handle the exposition of metadata own by the in progress submission. + * Describe step for DSpace Spring Rest. Expose and allow patching of the in progress submission metadata. It is + * configured via the config/submission-forms.xml file * * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) + * @author Andrea Bollini (andrea.bollini at 4science.it) */ public class DescribeStep extends org.dspace.submit.step.DescribeStep implements AbstractRestProcessingStep { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/ExtractMetadataStep.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/ExtractMetadataStep.java index 7353a9cf03..9f91ca9610 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/ExtractMetadataStep.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/ExtractMetadataStep.java @@ -35,6 +35,10 @@ import org.dspace.submit.step.ExtractionStep; import org.springframework.web.multipart.MultipartFile; /** + * This submission step allows to extract metadata from an uploaded file to enrich or initialize a submission. The + * processing is delegated to a list of extractor specialized by format (i.e. a Grobid extractor to get data from a PDF + * file, an extractor to get data from bibliographic file such as BibTeX, etc) + * * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) */ public class ExtractMetadataStep extends ExtractionStep implements UploadableStep { @@ -81,7 +85,7 @@ public class ExtractMetadataStep extends ExtractionStep implements UploadableSte return null; } - public RecordSet convertFields(RecordSet recordSet, Map fieldMap) { + private RecordSet convertFields(RecordSet recordSet, Map fieldMap) { RecordSet result = new RecordSet(); for (Record publication : recordSet.getRecords()) { for (String fieldName : fieldMap.keySet()) { diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/UploadStep.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/UploadStep.java index 8ca0e10bac..a602433c4d 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/UploadStep.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/UploadStep.java @@ -7,22 +7,32 @@ */ package org.dspace.app.rest.submit.step; +import java.io.BufferedInputStream; +import java.io.InputStream; import java.util.List; +import org.apache.log4j.Logger; +import org.dspace.app.rest.model.ErrorRest; import org.dspace.app.rest.model.patch.Operation; import org.dspace.app.rest.model.step.DataUpload; import org.dspace.app.rest.model.step.UploadBitstreamRest; +import org.dspace.app.rest.repository.WorkspaceItemRestRepository; import org.dspace.app.rest.submit.AbstractRestProcessingStep; import org.dspace.app.rest.submit.SubmissionService; +import org.dspace.app.rest.submit.UploadableStep; import org.dspace.app.rest.submit.factory.PatchOperationFactory; import org.dspace.app.rest.submit.factory.impl.PatchOperation; import org.dspace.app.util.SubmissionStepConfig; import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; import org.dspace.content.Bundle; +import org.dspace.content.InProgressSubmission; +import org.dspace.content.Item; import org.dspace.content.WorkspaceItem; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.services.model.Request; +import org.springframework.web.multipart.MultipartFile; /** * Upload step for DSpace Spring Rest. Expose information about the bitstream @@ -30,8 +40,10 @@ import org.dspace.services.model.Request; * * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) */ -public class UploadStep extends org.dspace.submit.step.UploadStep implements AbstractRestProcessingStep { +public class UploadStep extends org.dspace.submit.step.UploadStep + implements AbstractRestProcessingStep, UploadableStep { + private static final Logger log = Logger.getLogger(UploadStep.class); @Override public DataUpload getData(SubmissionService submissionService, WorkspaceItem obj, SubmissionStepConfig config) @@ -79,4 +91,54 @@ public class UploadStep extends org.dspace.submit.step.UploadStep implements Abs } + @Override + public ErrorRest upload(Context context, SubmissionService submissionService, SubmissionStepConfig stepConfig, + InProgressSubmission wsi, MultipartFile file, String extraField) { + + Bitstream source = null; + BitstreamFormat bf = null; + + Item item = wsi.getItem(); + List bundles = null; + try { + // do we already have a bundle? + bundles = itemService.getBundles(item, Constants.CONTENT_BUNDLE_NAME); + + InputStream inputStream = new BufferedInputStream(file.getInputStream()); + if (bundles.size() < 1) { + // set bundle's name to ORIGINAL + source = itemService.createSingleBitstream(context, inputStream, item, Constants.CONTENT_BUNDLE_NAME); + } else { + // we have a bundle already, just add bitstream + source = bitstreamService.create(context, bundles.get(0), inputStream); + } + + source.setName(context, extraField); + source.setSource(context, file.getOriginalFilename()); + + // Identify the format + bf = bitstreamFormatService.guessFormat(context, source); + source.setFormat(context, bf); + + // Update to DB + bitstreamService.update(context, source); + itemService.update(context, item); + + } catch (Exception e) { + log.error(e.getMessage(), e); + ErrorRest result = new ErrorRest(); + result.setMessage(e.getMessage()); + if (bundles != null && bundles.size() > 0) { + result.getPaths().add( + "/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + stepConfig.getId() + "/files/" + + bundles.get(0).getBitstreams().size()); + } else { + result.getPaths() + .add("/" + WorkspaceItemRestRepository.OPERATION_PATH_SECTIONS + "/" + stepConfig.getId()); + } + return result; + } + + return null; + } } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/validation/AbstractValidation.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/validation/AbstractValidation.java index cf97d044c4..49bf841d59 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/validation/AbstractValidation.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/validation/AbstractValidation.java @@ -14,7 +14,7 @@ import org.apache.commons.lang.StringUtils; import org.dspace.app.rest.model.ErrorRest; /** - * Abstract class to manage errors on validation during submission process + * Abstract class to provide basic management of errors resulting from a validation on a submission * * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) */ @@ -24,6 +24,9 @@ public abstract class AbstractValidation implements Validation { private List errors = new ArrayList(); + /** + * An unique name to identify the validation implementation + */ public String getName() { return name; } @@ -32,6 +35,15 @@ public abstract class AbstractValidation implements Validation { this.name = name; } + /** + * Add an error message (i18nKey) for a specific json path + * + * @param i18nKey + * the validation error message as a key to internationalize + * @param path + * the json path that identify the wrong data in the submission. It could be as specific as a single + * value in a multivalued attribute or general of a "whole" section + */ public void addError(String i18nKey, String path) { boolean found = false; if (StringUtils.isNotBlank(i18nKey)) { @@ -51,6 +63,11 @@ public abstract class AbstractValidation implements Validation { } } + /** + * Expose the identified errors + * + * @return the list of identified {@link ErrorRest} + */ public List getErrors() { return errors; } diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/validation/LicenseValidation.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/validation/LicenseValidation.java index 1ce6cb35de..12d9ae99c9 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/validation/LicenseValidation.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/submit/step/validation/LicenseValidation.java @@ -23,7 +23,8 @@ import org.dspace.core.Constants; import org.springframework.beans.factory.annotation.Autowired; /** - * Execute check on license bundle + * This submission validation check that the license has been grant for the inprogress submission looking for the + * presence of a license bitstream in the license bundle, * * @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it) */ diff --git a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/MultipartFileSender.java b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/MultipartFileSender.java index 5133431b61..4ae836bccf 100644 --- a/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/MultipartFileSender.java +++ b/dspace-spring-rest/src/main/java/org/dspace/app/rest/utils/MultipartFileSender.java @@ -41,8 +41,8 @@ public class MultipartFileSender { private static final String MULTIPART_BOUNDARY = "MULTIPART_BYTERANGES"; private static final String CONTENT_TYPE_MULTITYPE_WITH_BOUNDARY = "multipart/byteranges; boundary=" + MULTIPART_BOUNDARY; - private static final String CONTENT_DISPOSITION_INLINE = "inline"; - private static final String CONTENT_DISPOSITION_ATTACHMENT = "attachment"; + public static final String CONTENT_DISPOSITION_INLINE = "inline"; + public static final String CONTENT_DISPOSITION_ATTACHMENT = "attachment"; private static final String IF_NONE_MATCH = "If-None-Match"; private static final String IF_MODIFIED_SINCE = "If-Modified-Since"; private static final String ETAG = "ETag"; @@ -134,6 +134,10 @@ public class MultipartFileSender { } return this; } + public MultipartFileSender withDisposition(String contentDisposition) { + this.disposition = contentDisposition; + return this; + } public void serveResource() throws IOException { @@ -172,9 +176,9 @@ public class MultipartFileSender { CONTENT_DISPOSITION_ATTACHMENT; } - response.setHeader(CONTENT_DISPOSITION, String.format(CONTENT_DISPOSITION_FORMAT, disposition, fileName)); - log.debug("Content-Disposition : {}", disposition); } + response.setHeader(CONTENT_DISPOSITION, String.format(CONTENT_DISPOSITION_FORMAT, disposition, fileName)); + log.debug("Content-Disposition : {}", disposition); // Content phase if (METHOD_HEAD.equals(request.getMethod())) { diff --git a/dspace-spring-rest/src/main/webapp/js/hal/http/client.js b/dspace-spring-rest/src/main/webapp/js/hal/http/client.js index 9e1871abae..20f80156aa 100644 --- a/dspace-spring-rest/src/main/webapp/js/hal/http/client.js +++ b/dspace-spring-rest/src/main/webapp/js/hal/http/client.js @@ -7,13 +7,55 @@ */ HAL.Http.Client = function(opts) { this.vent = opts.vent; - this.defaultHeaders = { 'Accept': 'application/hal+json, application/json, */*; q=0.01' }; - cookie = document.cookie.match('(^|;)\\s*' + 'MyHalBrowserToken' + '\\s*=\\s*([^;]+)'); - cookie ? this.defaultHeaders.Authorization = 'Bearer ' + cookie.pop() : ''; + this.defaultHeaders = {'Accept': 'application/hal+json, application/json, */*; q=0.01'}; + var authorizationHeader = getAuthorizationHeader(); + authorizationHeader ? this.defaultHeaders.Authorization = authorizationHeader : ''; console.log(this.defaultHeaders); this.headers = this.defaultHeaders; }; +function getAuthorizationHeader() { + var cookie = document.cookie.match('(^|;)\\s*' + 'MyHalBrowserToken' + '\\s*=\\s*([^;]+)'); + if(cookie != undefined) { + return 'Bearer ' + cookie.pop(); + } else { + return undefined; + } +} +function downloadFile(url) { + var request = new XMLHttpRequest(); + request.open('GET', url, true); + request.responseType = 'blob'; + var authorizationHeader = getAuthorizationHeader(); + if (authorizationHeader != undefined) { + request.setRequestHeader("Authorization", authorizationHeader); + } + request.onload = function () { + // Only handle status code 200 + if (request.status === 200) { + // Try to find out the filename from the content disposition `filename` value + var disposition = request.getResponseHeader('content-disposition'); + var matches = /"([^"]*)"/.exec(disposition); + var filename = (matches != null && matches[1] ? matches[1] : 'content'); + // The actual download + var contentTypeHeader = request.getResponseHeader("content-type"); + if (contentTypeHeader === undefined || contentTypeHeader === "") { + contentTypeHeader = "application/octet-stream"; + } + var blob = new Blob([request.response], {type: contentTypeHeader}); + var link = document.createElement('a'); + link.href = window.URL.createObjectURL(blob); + link.download = filename; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + // some error handling should be done here... + }; + request.send(); +} + + HAL.Http.Client.prototype.get = function(url) { var self = this; this.vent.trigger('location-change', { url: url }); @@ -31,9 +73,14 @@ HAL.Http.Client.prototype.get = function(url) { headers: jqXHR.getAllResponseHeaders() }); } - }).error(function() { - self.vent.trigger('fail-response', { jqxhr: jqxhr }); - }); + }).error(function (response) { + self.vent.trigger('fail-response', {jqxhr: jqxhr}); + var contentTypeResponseHeader = jqxhr.getResponseHeader("content-type"); + if (contentTypeResponseHeader != undefined + && !contentTypeResponseHeader.startsWith("application/hal") + && !contentTypeResponseHeader.startsWith("application/json")) { + downloadFile(url); + }}); }; HAL.Http.Client.prototype.request = function(opts) { diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java new file mode 100644 index 0000000000..624152686a --- /dev/null +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/WorkspaceItemRestRepositoryIT.java @@ -0,0 +1,1661 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ +package org.dspace.app.rest; + +import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath; +import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.fileUpload; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import javax.ws.rs.core.MediaType; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.CharEncoding; +import org.dspace.app.rest.builder.BitstreamBuilder; +import org.dspace.app.rest.builder.CollectionBuilder; +import org.dspace.app.rest.builder.CommunityBuilder; +import org.dspace.app.rest.builder.EPersonBuilder; +import org.dspace.app.rest.builder.WorkspaceItemBuilder; +import org.dspace.app.rest.matcher.CollectionMatcher; +import org.dspace.app.rest.matcher.ItemMatcher; +import org.dspace.app.rest.matcher.WorkspaceItemMatcher; +import org.dspace.app.rest.model.patch.AddOperation; +import org.dspace.app.rest.model.patch.Operation; +import org.dspace.app.rest.model.patch.RemoveOperation; +import org.dspace.app.rest.model.patch.ReplaceOperation; +import org.dspace.app.rest.test.AbstractControllerIntegrationTest; +import org.dspace.content.Bitstream; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.Item; +import org.dspace.content.WorkspaceItem; +import org.dspace.eperson.EPerson; +import org.hamcrest.Matchers; +import org.junit.Test; +import org.springframework.mock.web.MockMultipartFile; + +/** + * Test suite for the WorkspaceItem endpoint + * @author Andrea Bollini (andrea.bollini at 4science.it) + * + */ +public class WorkspaceItemRestRepositoryIT extends AbstractControllerIntegrationTest { + + @Test + /** + * All the workspaceitem should be returned regardless of the collection where they were created + * + * @throws Exception + */ + public void findAllTest() throws Exception { + context.setCurrentUser(admin); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + + //2. Three workspace items in two different collections + WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 2") + .withIssueDate("2016-02-13") + .build(); + + WorkspaceItem workspaceItem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 3") + .withIssueDate("2016-02-13") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/submission/workspaceitems")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", Matchers.containsInAnyOrder( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, "Workspace Item 2", + "2016-02-13"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", + "2016-02-13")))) + .andExpect(jsonPath("$._links.self.href", Matchers.containsString("/api/submission/workspaceitems"))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(3))); + } + + @Test + /** + * The workspaceitem endpoint must provide proper pagination + * + * @throws Exception + */ + public void findAllWithPaginationTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + + //2. Three workspace items in two different collections + WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 2") + .withIssueDate("2016-02-13") + .build(); + + WorkspaceItem workspaceItem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 3") + .withIssueDate("2016-02-13") + .build(); + + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/submission/workspaceitems").param("size", "2")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.containsInAnyOrder( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, "Workspace Item 2", + "2016-02-13")))) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.not(Matchers.contains(WorkspaceItemMatcher + .matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", "2016-02-13"))))); + + getClient(token).perform(get("/api/submission/workspaceitems").param("size", "2").param("page", "1")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.contains(WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem3, + "Workspace Item 3", "2016-02-13")))) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.not(Matchers.contains( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, "Workspace Item 2", + "2016-02-13"))))) + .andExpect(jsonPath("$.page.size", is(2))).andExpect(jsonPath("$.page.totalElements", is(3))); + } + + @Test + /** + * The workspaceitem resource endpoint must expose the proper structure + * + * @throws Exception + */ + public void findOneTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. a workspace item + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())).andExpect(status().isOk()) + .andExpect(jsonPath("$", + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "Workspace Item 1", "2017-10-17", "ExtraEntry")))); + } + + @Test + /** + * The workspaceitem resource endpoint must expose the proper structure + * + * @throws Exception + */ + public void findOneRelsTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + //2. a workspace item + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withAuthor("Smith, Donald").withAuthor("Doe, John") + .withSubject("ExtraEntry") + .build(); + + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/collection")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers + .is(CollectionMatcher.matchCollectionEntry(col1.getName(), col1.getID(), col1.getHandle())))); + + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/item")).andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is(ItemMatcher.matchItemWithTitleAndDateIssued(witem.getItem(), + "Workspace Item 1", "2017-10-17")))); + + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID() + "/submissionDefinition")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$", Matchers.is(hasJsonPath("$.id", is("traditional"))))); + + } + + @Test + /** + * Check the response code for unexistent workspaceitem + * + * @throws Exception + */ + public void findOneWrongUUIDTest() throws Exception { + String token = getAuthToken(admin.getEmail(), password); + + getClient(token).perform(get("/api/submission/workspaceitems/" + UUID.randomUUID())) + .andExpect(status().isNotFound()); + } + + @Test + /** + * Removing a workspaceitem should result in delete of all the underline resources (item and bitstreams) + * + * @throws Exception + */ + public void deleteOneTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community with one collection. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, parentCommunity).withName("Collection 1").build(); + + //2. a workspace item + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + Item item = witem.getItem(); + + //Add a bitstream to the item + String bitstreamContent = "ThisIsSomeDummyText"; + Bitstream bitstream = null; + try (InputStream is = IOUtils.toInputStream(bitstreamContent, CharEncoding.UTF_8)) { + bitstream = BitstreamBuilder + .createBitstream(context, item, is) + .withName("Bitstream1") + .withMimeType("text/plain").build(); + } + + String token = getAuthToken(admin.getEmail(), password); + + //Delete the workspaceitem + getClient(token).perform(delete("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().is(204)); + + //Trying to get deleted item should fail with 404 + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().is(404)); + + //Trying to get deleted workspaceitem's item should fail with 404 + getClient().perform(get("/api/core/items/" + item.getID())) + .andExpect(status().is(404)); + + //Trying to get deleted workspaceitem's bitstream should fail with 404 + getClient().perform(get("/api/core/biststreams/" + bitstream.getID())) + .andExpect(status().is(404)); + } + + @Test + /** + * Create three workspaceitem with two different submitter and verify that the findBySubmitter return the proper + * list of workspaceitem for each submitter also paginating + * + * @throws Exception + */ + public void findBySubmitterTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + //2. create two users to use as submitters + EPerson submitter1 = EPersonBuilder.createEPerson(context) + .withEmail("submitter1@example.com") + .build(); + EPerson submitter2 = EPersonBuilder.createEPerson(context) + .withEmail("submitter2@example.com") + .build(); + + // create two workspaceitems with the first submitter + context.setCurrentUser(submitter1); + + + //3. Two workspace items in two different collections + WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 2") + .withIssueDate("2016-02-13") + .build(); + + //4. A workspaceitem for the second submitter + context.setCurrentUser(submitter2); + WorkspaceItem workspaceItem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col2) + .withTitle("Workspace Item 3") + .withIssueDate("2016-02-13") + .build(); + + // use our admin to retrieve all the workspace by submitter + String token = getAuthToken(admin.getEmail(), password); + + // the first submitter has two workspace + getClient(token).perform(get("/api/submission/workspaceitems/search/findBySubmitter") + .param("size", "20") + .param("uuid", submitter1.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.containsInAnyOrder( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, "Workspace Item 2", + "2016-02-13")))) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.not(Matchers.contains(WorkspaceItemMatcher + .matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", "2016-02-13"))))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(2))); + + // the first submitter has two workspace so if we paginate with a 1-size windows the page 1 will contains the + // second workspace + getClient(token).perform(get("/api/submission/workspaceitems/search/findBySubmitter") + .param("size", "1") + .param("page", "1") + .param("uuid", submitter1.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.contains(WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem2, + "Workspace Item 2", "2016-02-13")))) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.not(Matchers.contains( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem1, "Workspace Item 1", + "2017-10-17"), + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", + "2016-02-13"))))) + .andExpect(jsonPath("$.page.size", is(1))) + .andExpect(jsonPath("$.page.totalElements", is(2))); + + // the second submitter has a single workspace + getClient(token).perform(get("/api/submission/workspaceitems/search/findBySubmitter") + .param("size", "20") + .param("uuid", submitter2.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems", + Matchers.contains( + WorkspaceItemMatcher.matchItemWithTitleAndDateIssued(workspaceItem3, "Workspace Item 3", + "2016-02-13")))) + .andExpect(jsonPath("$.page.size", is(20))) + .andExpect(jsonPath("$.page.totalElements", is(1))); + } + + @Test + /** + * Test the creation of workspaceitem POSTing to the resource collection endpoint. It should respect the collection + * param if present or use a default if it is not used + * + * @throws Exception + */ + public void createEmptyWorkspateItemTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + // create a workspaceitem explicitly in the col1 + getClient(authToken).perform(post("/api/submission/workspaceitems") + .param("collection", col1.getID().toString())) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$._embedded.collection.id", is(col1.getID().toString()))); + + // create a workspaceitem explicitly in the col2 + getClient(authToken).perform(post("/api/submission/workspaceitems") + .param("collection", col2.getID().toString())) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$._embedded.collection.id", is(col2.getID().toString()))); + + // create a workspaceitem without an explicit collection, this will go in the first valid collection for the + // user: the col1 + getClient(authToken).perform(post("/api/submission/workspaceitems")) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$._embedded.collection.id", is(col1.getID().toString()))); + + // TODO cleanup the context!!! + } + + @Test + /** + * Test the creation of workspaceitems POSTing to the resource collection endpoint a bibtex file + * + * @throws Exception + */ + public void createMultipleWorkspaceItemFromFileTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + Collection col2 = CollectionBuilder.createCollection(context, child1).withName("Collection 2").build(); + + String authToken = getAuthToken(admin.getEmail(), password); + + InputStream bibtex = getClass().getResourceAsStream("bibtex-test.bib"); + final MockMultipartFile bibtexFile = new MockMultipartFile("file", bibtex); + + // bulk create workspaceitems in the default collection (col1) + getClient(authToken).perform(fileUpload("/api/submission/workspaceitems") + .file(bibtexFile) + .param("extraField", "bibtex-test.bib")) + // bulk create should return 200, 201 (created) is better for single resource + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", + is("My Article"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id", is(col1.getID().toString()))) + .andExpect(jsonPath("$._embedded.workspaceitems[1].sections.traditionalpageone['dc.title'][0].value", + is("My Article 2"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[1]._embedded.collection.id", is(col1.getID().toString()))) + .andExpect(jsonPath("$._embedded.workspaceitems[2].sections.traditionalpageone['dc.title'][0].value", + is("My Article 3"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[2]._embedded.collection.id", is(col1.getID().toString()))) + ; + + // bulk create workspaceitems explicitly in the col2 + getClient(authToken).perform(fileUpload("/api/submission/workspaceitems") + .file(bibtexFile) + .param("collection", col2.getID().toString())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$._embedded.workspaceitems[0].sections.traditionalpageone['dc.title'][0].value", + is("My Article"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[0]._embedded.collection.id", is(col2.getID().toString()))) + .andExpect(jsonPath("$._embedded.workspaceitems[1].sections.traditionalpageone['dc.title'][0].value", + is("My Article 2"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[1]._embedded.collection.id", is(col2.getID().toString()))) + .andExpect(jsonPath("$._embedded.workspaceitems[2].sections.traditionalpageone['dc.title'][0].value", + is("My Article 3"))) + .andExpect( + jsonPath("$._embedded.workspaceitems[2]._embedded.collection.id", is(col2.getID().toString()))) + ; + + bibtex.close(); + } + + @Test + /** + * Test the creation of a workspaceitem POSTing to the resource collection endpoint a PDF file. As a single item + * will be created we expect to have the pdf file stored as a bitstream + * + * @throws Exception + */ + public void createWorkspaceItemFromPDFFileTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + String authToken = getAuthToken(admin.getEmail(), password); + + InputStream pdf = getClass().getResourceAsStream("simple-article.pdf"); + final MockMultipartFile pdfFile = new MockMultipartFile("file", "/local/path/myfile.pdf", "application/pdf", + pdf); + + // bulk create a workspaceitem + getClient(authToken).perform(fileUpload("/api/submission/workspaceitems") + .file(pdfFile) + .param("extraField", "sample-article.pdf")) + // bulk create should return 200, 201 (created) is better for single resource + .andExpect(status().isOk()) + //FIXME it will be nice to setup a mock grobid server for end to end testing + // no metadata for now +// .andExpect(jsonPath("$._embedded.workspaceitems[0]._embedded.traditionalpageone['dc.title'][0].value", +// is("This is a simple test file"))) + // we can just check that the pdf is stored in the item + .andExpect( + jsonPath("$._embedded.workspaceitems[0].sections.upload.files[0].metadata['dc.title'][0].value", + is("sample-article.pdf"))) + .andExpect(jsonPath( + "$._embedded.workspaceitems[0].sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/myfile.pdf"))) + ; + + pdf.close(); + } + + @Test + /** + * Test the exposition of validation error for missing required metadata both at the creation time than on existent + * workspaceitems + * + * @throws Exception + */ + public void validationErrorsRequiredMetadataTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem workspaceItem1 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .build(); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + workspaceItem1.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + ; + + WorkspaceItem workspaceItem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 2") + .build(); + + getClient(authToken).perform(get("/api/submission/workspaceitems/" + workspaceItem2.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(false))) + .andExpect(jsonPath("$.errors[?(@.message=='error.validation.required')]", + Matchers.contains( + hasJsonPath("$.paths", Matchers.contains( + hasJsonPath("$", Matchers.is("/sections/traditionalpageone/dc.date.issued")) + ))))) + ; + + // create an empty workspaceitem explicitly in the col1, check validation on creation + getClient(authToken).perform(post("/api/submission/workspaceitems") + .param("collection", col1.getID().toString())) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.status", is(false))) + // title and author are required in the first panel + // the json path with a @ selector always return an array + .andExpect(jsonPath("$.errors[?(@.message=='error.validation.required')]", + Matchers.contains( + hasJsonPath("$.paths", Matchers.containsInAnyOrder( + hasJsonPath("$", Matchers.is("/sections/traditionalpageone/dc.title")), + hasJsonPath("$", Matchers.is("/sections/traditionalpageone/dc.date.issued")) + ))))) + ; + } + + @Test + /** + * Test the update of metadata + * + * @throws Exception + */ + public void patchUpdateMetadataTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withSubject("ExtraEntry") + .build(); + + // a simple patch to update an existent metadata + List updateTitle = new ArrayList(); + Map value = new HashMap(); + value.put("value", "New Title"); + updateTitle.add(new ReplaceOperation("/sections/traditionalpageone/dc.title/0", value)); + + String patchBody = getPatchContent(updateTitle); + + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$", + // check the new title and untouched values + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "New Title", "2017-10-17", "ExtraEntry")))); + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$", + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "New Title", "2017-10-17", "ExtraEntry")))) + ; + } + + @Test + /** + * Test delete of a metadata + * + * @throws Exception + */ + public void patchDeleteMetadataTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withSubject("ExtraEntry") + .build(); + + WorkspaceItem witemMultipleSubjects = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withSubject("Subject1") + .withSubject("Subject2") + .withSubject("Subject3") + .withSubject("Subject4") + .build(); + + WorkspaceItem witemWithTitleDateAndSubjects = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Workspace Item 1") + .withIssueDate("2017-10-17") + .withSubject("Subject1") + .withSubject("Subject2") + .withSubject("Subject3") + .withSubject("Subject4") + .build(); + + // try to remove the title + List removeTitle = new ArrayList(); + removeTitle.add(new RemoveOperation("/sections/traditionalpageone/dc.title/0")); + + String patchBody = getPatchContent(removeTitle); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(false))) + .andExpect(jsonPath("$.errors[?(@.message=='error.validation.required')]", + Matchers.contains(hasJsonPath("$.paths", + Matchers.contains( + hasJsonPath("$", + Matchers.is("/sections/traditionalpageone/dc.title"))))))) + .andExpect(jsonPath("$", + // check the new title and untouched values + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + null, "2017-10-17", "ExtraEntry")))); + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(false))) + .andExpect(jsonPath("$.errors[?(@.message=='error.validation.required')]", + Matchers.contains( + hasJsonPath("$.paths", Matchers.contains( + hasJsonPath("$", Matchers.is("/sections/traditionalpageone/dc.title")) + ))))) + .andExpect(jsonPath("$", + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + null, "2017-10-17", "ExtraEntry")))) + ; + + // try to remove a metadata in a specific position + List removeMidSubject = new ArrayList(); + removeMidSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/1")); + + patchBody = getPatchContent(removeMidSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemMultipleSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject3"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Subject4"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemMultipleSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject3"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Subject4"))) + ; + + List removeFirstSubject = new ArrayList(); + removeFirstSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/0")); + + patchBody = getPatchContent(removeFirstSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemMultipleSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject3"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject4"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemMultipleSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject3"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject4"))) + ; + + List removeLastSubject = new ArrayList(); + removeLastSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/1")); + + patchBody = getPatchContent(removeLastSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemMultipleSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject3"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemMultipleSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject3"))) + ; + + List removeFinalSubject = new ArrayList(); + removeFinalSubject.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject/0")); + + patchBody = getPatchContent(removeFinalSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemMultipleSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject']").doesNotExist()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemMultipleSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject']").doesNotExist()) + ; + + // remove all the subjects with a single operation + List removeSubjectsAllAtOnce = new ArrayList(); + removeSubjectsAllAtOnce.add(new RemoveOperation("/sections/traditionalpagetwo/dc.subject")); + + patchBody = getPatchContent(removeSubjectsAllAtOnce); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witemWithTitleDateAndSubjects.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject']").doesNotExist()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witemWithTitleDateAndSubjects.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject']").doesNotExist()) + ; + } + + @Test + /** + * Test the addition of metadata + * + * @throws Exception + */ + public void patchAddMetadataTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withIssueDate("2017-10-17") + .withSubject("ExtraEntry") + .build(); + + + // try to add the title + List addTitle = new ArrayList(); + // create a list of values to use in add operation + List> values = new ArrayList>(); + Map value = new HashMap(); + value.put("value", "New Title"); + values.add(value); + addTitle.add(new AddOperation("/sections/traditionalpageone/dc.title", values)); + + String patchBody = getPatchContent(addTitle); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$", + // check if the new title if back and the other values untouched + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "New Title", "2017-10-17", "ExtraEntry")))); + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$", + Matchers.is(WorkspaceItemMatcher.matchItemWithTitleAndDateIssuedAndSubject(witem, + "New Title", "2017-10-17", "ExtraEntry")))) + ; + } + + @Test + /** + * Test the addition of metadata + * + * @throws Exception + */ + public void patchAddMultipleMetadataValuesTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .build(); + + // try to add multiple subjects at once + List addSubjects = new ArrayList(); + // create a list of values to use in add operation + List> values = new ArrayList>(); + Map value1 = new HashMap(); + value1.put("value", "Subject1"); + Map value2 = new HashMap(); + value2.put("value", "Subject2"); + values.add(value1); + values.add(value2); + + addSubjects.add(new AddOperation("/sections/traditionalpagetwo/dc.subject", values)); + + String patchBody = getPatchContent(addSubjects); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject2"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject2"))) + ; + + // add a subject in the first position + List addFirstSubject = new ArrayList(); + Map firstSubject = new HashMap(); + firstSubject.put("value", "First Subject"); + + addFirstSubject.add(new AddOperation("/sections/traditionalpagetwo/dc.subject/0", firstSubject)); + + patchBody = getPatchContent(addFirstSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", + is("Subject2"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Subject2"))) + ; + + // add a subject in a central position + List addMidSubject = new ArrayList(); + Map midSubject = new HashMap(); + midSubject.put("value", "Mid Subject"); + + addMidSubject.add(new AddOperation("/sections/traditionalpagetwo/dc.subject/2", midSubject)); + + patchBody = getPatchContent(addMidSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", + is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", + is("Subject2"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", is("Subject2"))) + ; + + // append a last subject without specifying the index + List addLastSubject = new ArrayList(); + Map lastSubject = new HashMap(); + lastSubject.put("value", "Last Subject"); + + addLastSubject.add(new AddOperation("/sections/traditionalpagetwo/dc.subject/4", lastSubject)); + + patchBody = getPatchContent(addLastSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", + is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", + is("Subject2"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][4].value", + is("Last Subject"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", is("Subject2"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][4].value", is("Last Subject"))) + ; + + // append a last subject without specifying the index + List addFinalSubject = new ArrayList(); + Map finalSubject = new HashMap(); + finalSubject.put("value", "Final Subject"); + + addFinalSubject.add(new AddOperation("/sections/traditionalpagetwo/dc.subject/-", finalSubject)); + + patchBody = getPatchContent(addFinalSubject); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", + is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", + is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", + is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", + is("Subject2"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][4].value", + is("Last Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][5].value", + is("Final Subject"))) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][0].value", is("First Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][1].value", is("Subject1"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][2].value", is("Mid Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][3].value", is("Subject2"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][4].value", is("Last Subject"))) + .andExpect(jsonPath("$.sections.traditionalpagetwo['dc.subject'][5].value", is("Final Subject"))) + ; + } + + @Test + /** + * Test the acceptance of the deposit license + * + * @throws Exception + */ + public void patchAcceptLicenseTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem witem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 2") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem witem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 3") + .withIssueDate("2017-10-17") + .build(); + + WorkspaceItem witem4 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 4") + .withIssueDate("2017-10-17") + .build(); + + // check that our workspaceitems come without a license (all are build in the same way, just check the first) + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // try to grant the license with an add operation + List addGrant = new ArrayList(); + addGrant.add(new AddOperation("/sections/license/granted", true)); + + String patchBody = getPatchContent(addGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // try to grant the license with an add operation supplying a string instead than a boolean + List addGrantString = new ArrayList(); + addGrantString.add(new AddOperation("/sections/license/granted", "true")); + + patchBody = getPatchContent(addGrantString); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem2.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem2.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // try to grant the license with a replace operation + List replaceGrant = new ArrayList(); + replaceGrant.add(new ReplaceOperation("/sections/license/granted", true)); + + patchBody = getPatchContent(replaceGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem3.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem3.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // try to grant the license with a replace operation supplying a string + List replaceGrantString = new ArrayList(); + replaceGrant.add(new ReplaceOperation("/sections/license/granted", "true")); + + patchBody = getPatchContent(replaceGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem4.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem4.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + } + + @Test + /** + * Test the reject of the deposit license + * + * @throws Exception + */ + public void patchRejectLicenseTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .grantLicense() + .build(); + + WorkspaceItem witem2 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 2") + .withIssueDate("2017-10-17") + .grantLicense() + .build(); + + WorkspaceItem witem3 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 3") + .withIssueDate("2017-10-17") + .grantLicense() + .build(); + + WorkspaceItem witem4 = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem 4") + .withIssueDate("2017-10-17") + .grantLicense() + .build(); + + // check that our workspaceitems come with a license (all are build in the same way, just check the first) + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.license.granted", + is(true))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isNotEmpty()) + .andExpect(jsonPath("$.sections.license.url").isNotEmpty()) + ; + + // try to reject the license with an add operation + List addGrant = new ArrayList(); + addGrant.add(new AddOperation("/sections/license/granted", false)); + + String patchBody = getPatchContent(addGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // try to reject the license with an add operation supplying a string instead than a boolean + List addGrantString = new ArrayList(); + addGrantString.add(new AddOperation("/sections/license/granted", "false")); + + patchBody = getPatchContent(addGrantString); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem2.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem2.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // try to reject the license with a replace operation + List replaceGrant = new ArrayList(); + replaceGrant.add(new ReplaceOperation("/sections/license/granted", false)); + + patchBody = getPatchContent(replaceGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem3.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem3.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // try to reject the license with a replace operation supplying a string + List replaceGrantString = new ArrayList(); + replaceGrant.add(new ReplaceOperation("/sections/license/granted", "false")); + + patchBody = getPatchContent(replaceGrant); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem4.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + // verify that the patch changes have been persisted + getClient().perform(get("/api/submission/workspaceitems/" + witem4.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status", is(true))) + .andExpect(jsonPath("$.errors").doesNotExist()) + .andExpect(jsonPath("$.sections.license.granted", + is(false))) + .andExpect(jsonPath("$.sections.license.acceptanceDate").isEmpty()) + .andExpect(jsonPath("$.sections.license.url").isEmpty()) + ; + + } + + @Test + /** + * Test update of bitstream metadata in the upload section + * + * @throws Exception + */ + public void patchUploadTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + String authToken = getAuthToken(admin.getEmail(), password); + + InputStream pdf = getClass().getResourceAsStream("simple-article.pdf"); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .withFulltext("simple-article.pdf", "/local/path/simple-article.pdf", pdf) + .build(); + + // check the file metadata + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/simple-article.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("simple-article.pdf"))) + ; + + // try to change the filename and add a description + List addOpts = new ArrayList(); + Map value = new HashMap(); + value.put("value", "newfilename.pdf"); + Map valueDesc = new HashMap(); + valueDesc.put("value", "Description"); + List valueDescs = new ArrayList(); + valueDescs.add(valueDesc); + addOpts.add(new AddOperation("/sections/upload/files/0/metadata/dc.title/0", value)); + addOpts.add(new AddOperation("/sections/upload/files/0/metadata/dc.description", valueDescs)); + + String patchBody = getPatchContent(addOpts); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + // is the source still here? + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/simple-article.pdf"))) + // check the new filename + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("newfilename.pdf"))) + // check the description + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.description'][0].value", + is("Description"))) + ; + + // check that changes persist + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source'][0].value", + is("/local/path/simple-article.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("newfilename.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.description'][0].value", + is("Description"))) + ; + + // try to remove the description and the source now + List removeOpts = new ArrayList(); + removeOpts.add(new RemoveOperation("/sections/upload/files/0/metadata/dc.source/0")); + removeOpts.add(new RemoveOperation("/sections/upload/files/0/metadata/dc.description")); + + patchBody = getPatchContent(removeOpts); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + // check the removed source + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source']").doesNotExist()) + // check the filename still here + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("newfilename.pdf"))) + // check the removed description + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.description']").doesNotExist()) + ; + + // check that changes persist + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.source']").doesNotExist()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("newfilename.pdf"))) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.description']").doesNotExist()) ; + + // try to update the filename with an update opt + List updateOpts = new ArrayList(); + Map updateValue = new HashMap(); + updateValue.put("value", "another-filename.pdf"); + updateOpts.add(new ReplaceOperation("/sections/upload/files/0/metadata/dc.title/0", updateValue)); + + patchBody = getPatchContent(updateOpts); + getClient(authToken).perform(patch("/api/submission/workspaceitems/" + witem.getID()) + .content(patchBody) + .contentType(MediaType.APPLICATION_JSON_PATCH_JSON)) + .andExpect(status().isOk()) + // check the filename still here + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("another-filename.pdf"))) + ; + + // check that changes persist + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("another-filename.pdf"))) + ; + } + + @Test + /** + * Test the upload of files in the upload over section + * + * @throws Exception + */ + public void uploadTest() throws Exception { + context.turnOffAuthorisationSystem(); + + //** GIVEN ** + //1. A community-collection structure with one parent community with sub-community and two collections. + parentCommunity = CommunityBuilder.createCommunity(context) + .withName("Parent Community") + .build(); + Community child1 = CommunityBuilder.createSubCommunity(context, parentCommunity) + .withName("Sub Community") + .build(); + Collection col1 = CollectionBuilder.createCollection(context, child1).withName("Collection 1").build(); + + String authToken = getAuthToken(admin.getEmail(), password); + + WorkspaceItem witem = WorkspaceItemBuilder.createWorkspaceItem(context, col1) + .withTitle("Test WorkspaceItem") + .withIssueDate("2017-10-17") + .build(); + + InputStream pdf = getClass().getResourceAsStream("simple-article.pdf"); + final MockMultipartFile pdfFile = new MockMultipartFile("file", pdf); + + // upload the file in our workspaceitem + getClient(authToken).perform(fileUpload("/api/submission/workspaceitems/" + witem.getID()) + .file(pdfFile) + .param("extraField", "sample-article.pdf")) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("sample-article.pdf"))) + ; + + // check the file metadata + getClient().perform(get("/api/submission/workspaceitems/" + witem.getID())) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.sections.upload.files[0].metadata['dc.title'][0].value", + is("sample-article.pdf"))) + ; + } + +} diff --git a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java index 73ad1c7af1..4d73d23b19 100644 --- a/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java +++ b/dspace-spring-rest/src/test/java/org/dspace/app/rest/builder/WorkspaceItemBuilder.java @@ -7,10 +7,18 @@ */ package org.dspace.app.rest.builder; +import java.io.InputStream; + +import org.dspace.content.Bitstream; import org.dspace.content.Collection; +import org.dspace.content.DCDate; +import org.dspace.content.Item; +import org.dspace.content.LicenseUtils; +import org.dspace.content.MetadataSchema; import org.dspace.content.WorkspaceItem; import org.dspace.content.service.WorkspaceItemService; import org.dspace.core.Context; +import org.dspace.eperson.EPerson; /** * Builder to construct WorkspaceItem objects @@ -70,4 +78,68 @@ public class WorkspaceItemBuilder extends AbstractBuilder matchProperties(WorkspaceItem witem) { + return allOf( + hasJsonPath("$.id", is(witem.getID())), + hasJsonPath("$.type", is("workspaceitem")) + ); + } + + /** + * Check that the required links are present + * + * @param witem + * the workspaceitem + * @return + */ + public static Matcher matchLinks(WorkspaceItem witem) { + return allOf( + hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "submission/workspaceitems/" + witem.getID())), + hasJsonPath("$._links.item.href", startsWith(REST_SERVER_URL)), + hasJsonPath("$._links.collection.href", startsWith(REST_SERVER_URL)), + hasJsonPath("$._links.submitter.href", startsWith(REST_SERVER_URL)), + hasJsonPath("$._links.submissionDefinition.href", startsWith(REST_SERVER_URL))); + } +} diff --git a/dspace-spring-rest/src/test/resources/org/dspace/app/rest/bibtex-test.bib b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/bibtex-test.bib new file mode 100644 index 0000000000..4d197ff90f --- /dev/null +++ b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/bibtex-test.bib @@ -0,0 +1,14 @@ +@misc{ Nobody01, + author = "Nobody Jr", + title = "My Article", + year = "2006" } + +@misc{ Nobody02, + author = "Nobody Jr", + title = "My Article 2", + year = "2006" } + +@misc{ Nobody03, + author = "Nobody Jr", + title = "My Article 3", + year = "2018" } diff --git a/dspace-spring-rest/src/test/resources/org/dspace/app/rest/simple-article.pdf b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/simple-article.pdf new file mode 100644 index 0000000000..abefe17f93 Binary files /dev/null and b/dspace-spring-rest/src/test/resources/org/dspace/app/rest/simple-article.pdf differ diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index c38847ac07..f8a4930e61 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -1368,7 +1368,6 @@ websvc.opensearch.formats = html,atom,rss # The 'webui.*' setting is for the JSPUI, and # the 'xmlui.*' setting is for the XMLUI webui.content_disposition_threshold = 8388608 -xmlui.content_disposition_threshold = 8388608 #### Multi-file HTML document/site settings ##### diff --git a/dspace/config/modules/rest.cfg b/dspace/config/modules/rest.cfg index b209d080fc..c8ac235dc9 100644 --- a/dspace/config/modules/rest.cfg +++ b/dspace/config/modules/rest.cfg @@ -40,10 +40,11 @@ rest.report-url.item-query = static/reports/query.html #rest.report-url.custom = ##### database specific way to format a regex SQL clause ##### -# The REST Report Tools may pass a regular expression test to the database. +# The REST Report Tools may pass a regular expression test to the database. # The following configuration setting will construct a SQL regular expression test appropriate to your database engine rest.regex-clause = text_value ~ ? + ##### Configure REST Report Filters ##### # A filter contains a set of tests that will be applied to an item to determine its inclusion in a particular report. # Private items and withdrawn items are frequently excluded from DSpace reports. diff --git a/dspace/pom.xml b/dspace/pom.xml index bf33e91a4c..3780d02fa0 100644 --- a/dspace/pom.xml +++ b/dspace/pom.xml @@ -213,6 +213,7 @@ ${project.parent.basedir}/dspace-api/src/main/java + ${project.parent.basedir}/dspace-api/target/generated-sources/annotations ${project.parent.basedir}/dspace-oai/src/main/java ${project.parent.basedir}/dspace-rdf/src/main/java ${project.parent.basedir}/dspace-rest/src/main/java diff --git a/pom.xml b/pom.xml index 47cab720c2..88dfeec6d0 100644 --- a/pom.xml +++ b/pom.xml @@ -196,6 +196,9 @@ + + src/main/java + ${root.basedir}/checkstyle.xml ${project.build.sourceEncoding} true @@ -1037,6 +1040,12 @@ ${hibernate.version} + + org.hibernate + hibernate-jpamodelgen + ${hibernate.version} + + org.hibernate hibernate-ehcache