mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
459 lines
21 KiB
Java
459 lines
21 KiB
Java
/**
|
|
* The contents of this file are subject to the license and copyright
|
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
|
* tree and available online at
|
|
*
|
|
* http://www.dspace.org/license/
|
|
*/
|
|
package org.dspace.content;
|
|
|
|
import java.sql.SQLException;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
|
|
import org.apache.commons.collections4.CollectionUtils;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
import org.apache.logging.log4j.LogManager;
|
|
import org.apache.logging.log4j.Logger;
|
|
import org.dspace.authorize.AuthorizeException;
|
|
import org.dspace.authorize.service.AuthorizeService;
|
|
import org.dspace.content.dao.RelationshipDAO;
|
|
import org.dspace.content.service.ItemService;
|
|
import org.dspace.content.service.RelationshipService;
|
|
import org.dspace.content.service.RelationshipTypeService;
|
|
import org.dspace.content.virtual.VirtualMetadataPopulator;
|
|
import org.dspace.core.Constants;
|
|
import org.dspace.core.Context;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
public class RelationshipServiceImpl implements RelationshipService {
|
|
|
|
private static final Logger log = LogManager.getLogger();
|
|
|
|
@Autowired(required = true)
|
|
protected RelationshipDAO relationshipDAO;
|
|
|
|
@Autowired(required = true)
|
|
protected AuthorizeService authorizeService;
|
|
|
|
@Autowired(required = true)
|
|
protected ItemService itemService;
|
|
|
|
@Autowired(required = true)
|
|
protected RelationshipTypeService relationshipTypeService;
|
|
|
|
@Autowired
|
|
private VirtualMetadataPopulator virtualMetadataPopulator;
|
|
|
|
@Override
|
|
public Relationship create(Context context) throws SQLException, AuthorizeException {
|
|
if (!authorizeService.isAdmin(context)) {
|
|
throw new AuthorizeException(
|
|
"Only administrators can modify relationship");
|
|
}
|
|
return relationshipDAO.create(context, new Relationship());
|
|
}
|
|
|
|
@Override
|
|
public Relationship create(Context c, Item leftItem, Item rightItem, RelationshipType relationshipType,
|
|
int leftPlace, int rightPlace) throws AuthorizeException, SQLException {
|
|
return create(c, leftItem, rightItem, relationshipType, leftPlace, rightPlace, null, null);
|
|
}
|
|
|
|
@Override
|
|
public Relationship create(Context c, Item leftItem, Item rightItem, RelationshipType relationshipType,
|
|
int leftPlace, int rightPlace, String leftwardValue, String rightwardValue)
|
|
throws AuthorizeException, SQLException {
|
|
Relationship relationship = new Relationship();
|
|
relationship.setLeftItem(leftItem);
|
|
relationship.setRightItem(rightItem);
|
|
relationship.setRelationshipType(relationshipType);
|
|
relationship.setLeftPlace(leftPlace);
|
|
relationship.setRightPlace(rightPlace);
|
|
relationship.setLeftwardValue(leftwardValue);
|
|
relationship.setRightwardValue(rightwardValue);
|
|
return create(c, relationship);
|
|
}
|
|
|
|
@Override
|
|
public Relationship create(Context context, Relationship relationship) throws SQLException, AuthorizeException {
|
|
if (isRelationshipValidToCreate(context, relationship)) {
|
|
if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) ||
|
|
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
|
|
// This order of execution should be handled in the creation (create, updateplace, update relationship)
|
|
// for a proper place allocation
|
|
Relationship relationshipToReturn = relationshipDAO.create(context, relationship);
|
|
updatePlaceInRelationship(context, relationshipToReturn);
|
|
update(context, relationshipToReturn);
|
|
return relationshipToReturn;
|
|
} else {
|
|
throw new AuthorizeException(
|
|
"You do not have write rights on this relationship's items");
|
|
}
|
|
|
|
} else {
|
|
throw new IllegalArgumentException("The relationship given was not valid");
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void updatePlaceInRelationship(Context context, Relationship relationship)
|
|
throws SQLException, AuthorizeException {
|
|
Item leftItem = relationship.getLeftItem();
|
|
// Max value is used to ensure that these will get added to the back of the list and thus receive the highest
|
|
// (last) place as it's set to a -1 for creation
|
|
if (relationship.getLeftPlace() == -1) {
|
|
relationship.setLeftPlace(Integer.MAX_VALUE);
|
|
}
|
|
Item rightItem = relationship.getRightItem();
|
|
if (relationship.getRightPlace() == -1) {
|
|
relationship.setRightPlace(Integer.MAX_VALUE);
|
|
}
|
|
List<Relationship> leftRelationships = findByItemAndRelationshipType(context,
|
|
leftItem,
|
|
relationship.getRelationshipType(), true);
|
|
List<Relationship> rightRelationships = findByItemAndRelationshipType(context,
|
|
rightItem,
|
|
relationship.getRelationshipType(),
|
|
false);
|
|
|
|
// These relationships are only deleted from the temporary lists incase they're present in them so that we can
|
|
// properly perform our place calculation later down the line in this method.
|
|
if (leftRelationships.contains(relationship)) {
|
|
leftRelationships.remove(relationship);
|
|
}
|
|
if (rightRelationships.contains(relationship)) {
|
|
rightRelationships.remove(relationship);
|
|
}
|
|
context.turnOffAuthorisationSystem();
|
|
//If useForPlace for the leftwardType is false for the relationshipType,
|
|
// we need to sort the relationships here based on leftplace.
|
|
if (!virtualMetadataPopulator.isUseForPlaceTrueForRelationshipType(relationship.getRelationshipType(), true)) {
|
|
if (!leftRelationships.isEmpty()) {
|
|
leftRelationships.sort(Comparator.comparingInt(Relationship::getLeftPlace));
|
|
for (int i = 0; i < leftRelationships.size(); i++) {
|
|
leftRelationships.get(i).setLeftPlace(i);
|
|
}
|
|
relationship.setLeftPlace(leftRelationships.size());
|
|
} else {
|
|
relationship.setLeftPlace(0);
|
|
}
|
|
} else {
|
|
updateItem(context, leftItem);
|
|
|
|
}
|
|
|
|
//If useForPlace for the rightwardType is false for the relationshipType,
|
|
// we need to sort the relationships here based on the rightplace.
|
|
if (!virtualMetadataPopulator.isUseForPlaceTrueForRelationshipType(relationship.getRelationshipType(), false)) {
|
|
if (!rightRelationships.isEmpty()) {
|
|
rightRelationships.sort(Comparator.comparingInt(Relationship::getRightPlace));
|
|
for (int i = 0; i < rightRelationships.size(); i++) {
|
|
rightRelationships.get(i).setRightPlace(i);
|
|
}
|
|
relationship.setRightPlace(rightRelationships.size());
|
|
} else {
|
|
relationship.setRightPlace(0);
|
|
}
|
|
|
|
} else {
|
|
updateItem(context, rightItem);
|
|
|
|
}
|
|
context.restoreAuthSystemState();
|
|
|
|
}
|
|
|
|
@Override
|
|
public void updateItem(Context context, Item relatedItem)
|
|
throws SQLException, AuthorizeException {
|
|
relatedItem.setMetadataModified();
|
|
itemService.update(context, relatedItem);
|
|
}
|
|
|
|
@Override
|
|
public int findNextLeftPlaceByLeftItem(Context context, Item item) throws SQLException {
|
|
return relationshipDAO.findNextLeftPlaceByLeftItem(context, item);
|
|
}
|
|
|
|
@Override
|
|
public int findNextRightPlaceByRightItem(Context context, Item item) throws SQLException {
|
|
return relationshipDAO.findNextRightPlaceByRightItem(context, item);
|
|
}
|
|
|
|
private boolean isRelationshipValidToCreate(Context context, Relationship relationship) throws SQLException {
|
|
RelationshipType relationshipType = relationship.getRelationshipType();
|
|
|
|
if (!verifyEntityTypes(relationship.getLeftItem(), relationshipType.getLeftType())) {
|
|
log.warn("The relationship has been deemed invalid since the leftItem" +
|
|
" and leftType do no match on entityType");
|
|
logRelationshipTypeDetailsForError(relationshipType);
|
|
return false;
|
|
}
|
|
if (!verifyEntityTypes(relationship.getRightItem(), relationshipType.getRightType())) {
|
|
log.warn("The relationship has been deemed invalid since the rightItem" +
|
|
" and rightType do no match on entityType");
|
|
logRelationshipTypeDetailsForError(relationshipType);
|
|
return false;
|
|
}
|
|
if (!verifyMaxCardinality(context, relationship.getLeftItem(),
|
|
relationshipType.getLeftMaxCardinality(), relationshipType)) {
|
|
log.warn("The relationship has been deemed invalid since the left item has more" +
|
|
" relationships than the left max cardinality allows after we'd store this relationship");
|
|
logRelationshipTypeDetailsForError(relationshipType);
|
|
return false;
|
|
}
|
|
if (!verifyMaxCardinality(context, relationship.getRightItem(),
|
|
relationshipType.getRightMaxCardinality(), relationshipType)) {
|
|
log.warn("The relationship has been deemed invalid since the right item has more" +
|
|
" relationships than the right max cardinality allows after we'd store this relationship");
|
|
logRelationshipTypeDetailsForError(relationshipType);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void logRelationshipTypeDetailsForError(RelationshipType relationshipType) {
|
|
log.warn("The relationshipType's ID is: " + relationshipType.getID());
|
|
log.warn("The relationshipType's leftward type is: " + relationshipType.getLeftwardType());
|
|
log.warn("The relationshipType's rightward type is: " + relationshipType.getRightwardType());
|
|
log.warn("The relationshipType's left entityType label is: " + relationshipType.getLeftType().getLabel());
|
|
log.warn("The relationshipType's right entityType label is: " + relationshipType.getRightType().getLabel());
|
|
log.warn("The relationshipType's left min cardinality is: " + relationshipType.getLeftMinCardinality());
|
|
log.warn("The relationshipType's left max cardinality is: " + relationshipType.getLeftMaxCardinality());
|
|
log.warn("The relationshipType's right min cardinality is: " + relationshipType.getRightMinCardinality());
|
|
log.warn("The relationshipType's right max cardinality is: " + relationshipType.getRightMaxCardinality());
|
|
}
|
|
|
|
private boolean verifyMaxCardinality(Context context, Item itemToProcess,
|
|
Integer maxCardinality,
|
|
RelationshipType relationshipType) throws SQLException {
|
|
List<Relationship> rightRelationships = findByItemAndRelationshipType(context, itemToProcess, relationshipType,
|
|
false);
|
|
if (maxCardinality != null && rightRelationships.size() >= maxCardinality) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private boolean verifyEntityTypes(Item itemToProcess, EntityType entityTypeToProcess) {
|
|
List<MetadataValue> list = itemService.getMetadata(itemToProcess, "relationship", "type", null, Item.ANY);
|
|
if (list.isEmpty()) {
|
|
return false;
|
|
}
|
|
String leftEntityType = list.get(0).getValue();
|
|
return StringUtils.equals(leftEntityType, entityTypeToProcess.getLabel());
|
|
}
|
|
|
|
public Relationship find(Context context, int id) throws SQLException {
|
|
Relationship relationship = relationshipDAO.findByID(context, Relationship.class, id);
|
|
return relationship;
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findByItem(Context context, Item item) throws SQLException {
|
|
|
|
return findByItem(context, item, -1, -1);
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findByItem(Context context, Item item, Integer limit, Integer offset)
|
|
throws SQLException {
|
|
|
|
List<Relationship> list = relationshipDAO.findByItem(context, item, limit, offset);
|
|
|
|
list.sort((o1, o2) -> {
|
|
int relationshipType = o1.getRelationshipType().getLeftwardType()
|
|
.compareTo(o2.getRelationshipType().getLeftwardType());
|
|
if (relationshipType != 0) {
|
|
return relationshipType;
|
|
} else {
|
|
if (o1.getLeftItem() == item) {
|
|
return o1.getLeftPlace() - o2.getLeftPlace();
|
|
} else {
|
|
return o1.getRightPlace() - o2.getRightPlace();
|
|
}
|
|
}
|
|
});
|
|
return list;
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findAll(Context context) throws SQLException {
|
|
return findAll(context, -1, -1);
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findAll(Context context, Integer limit, Integer offset) throws SQLException {
|
|
return relationshipDAO.findAll(context, Relationship.class, limit, offset);
|
|
}
|
|
|
|
@Override
|
|
public void update(Context context, Relationship relationship) throws SQLException, AuthorizeException {
|
|
update(context, Collections.singletonList(relationship));
|
|
|
|
}
|
|
|
|
@Override
|
|
public void update(Context context, List<Relationship> relationships) throws SQLException, AuthorizeException {
|
|
if (CollectionUtils.isNotEmpty(relationships)) {
|
|
for (Relationship relationship : relationships) {
|
|
if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) ||
|
|
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
|
|
if (isRelationshipValidToCreate(context, relationship)) {
|
|
relationshipDAO.save(context, relationship);
|
|
}
|
|
} else {
|
|
throw new AuthorizeException("You do not have write rights on this relationship's items");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void delete(Context context, Relationship relationship) throws SQLException, AuthorizeException {
|
|
if (isRelationshipValidToDelete(context, relationship)) {
|
|
// To delete a relationship, a user must have WRITE permissions on one of the related Items
|
|
if (authorizeService.authorizeActionBoolean(context, relationship.getLeftItem(), Constants.WRITE) ||
|
|
authorizeService.authorizeActionBoolean(context, relationship.getRightItem(), Constants.WRITE)) {
|
|
relationshipDAO.delete(context, relationship);
|
|
updatePlaceInRelationship(context, relationship);
|
|
} else {
|
|
throw new AuthorizeException(
|
|
"You do not have write rights on this relationship's items");
|
|
}
|
|
|
|
} else {
|
|
throw new IllegalArgumentException("The relationship given was not valid");
|
|
}
|
|
}
|
|
|
|
private boolean isRelationshipValidToDelete(Context context, Relationship relationship) throws SQLException {
|
|
if (relationship == null) {
|
|
log.warn("The relationship has been deemed invalid since the relation was null");
|
|
return false;
|
|
}
|
|
if (relationship.getID() == null) {
|
|
log.warn("The relationship has been deemed invalid since the ID" +
|
|
" off the given relationship was null");
|
|
return false;
|
|
}
|
|
if (this.find(context, relationship.getID()) == null) {
|
|
log.warn("The relationship has been deemed invalid since the relationship" +
|
|
" is not present in the DB with the current ID");
|
|
logRelationshipTypeDetailsForError(relationship.getRelationshipType());
|
|
return false;
|
|
}
|
|
if (!checkMinCardinality(context, relationship.getLeftItem(),
|
|
relationship, relationship.getRelationshipType().getLeftMinCardinality(), true)) {
|
|
log.warn("The relationship has been deemed invalid since the leftMinCardinality" +
|
|
" constraint would be violated upon deletion");
|
|
logRelationshipTypeDetailsForError(relationship.getRelationshipType());
|
|
return false;
|
|
}
|
|
|
|
if (!checkMinCardinality(context, relationship.getRightItem(),
|
|
relationship, relationship.getRelationshipType().getRightMinCardinality(), false)) {
|
|
log.warn("The relationship has been deemed invalid since the rightMinCardinality" +
|
|
" constraint would be violated upon deletion");
|
|
logRelationshipTypeDetailsForError(relationship.getRelationshipType());
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private boolean checkMinCardinality(Context context, Item item,
|
|
Relationship relationship,
|
|
Integer minCardinality, boolean isLeft) throws SQLException {
|
|
List<Relationship> list = this.findByItemAndRelationshipType(context, item, relationship.getRelationshipType(),
|
|
isLeft, -1, -1);
|
|
if (minCardinality != null && !(list.size() > minCardinality)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
|
|
RelationshipType relationshipType, boolean isLeft)
|
|
throws SQLException {
|
|
return this.findByItemAndRelationshipType(context, item, relationshipType, isLeft, -1, -1);
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
|
|
RelationshipType relationshipType)
|
|
throws SQLException {
|
|
return relationshipDAO.findByItemAndRelationshipType(context, item, relationshipType, -1, -1);
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
|
|
RelationshipType relationshipType, int limit, int offset)
|
|
throws SQLException {
|
|
return relationshipDAO.findByItemAndRelationshipType(context, item, relationshipType, limit, offset);
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findByItemAndRelationshipType(Context context, Item item,
|
|
RelationshipType relationshipType, boolean isLeft,
|
|
int limit, int offset)
|
|
throws SQLException {
|
|
return relationshipDAO.findByItemAndRelationshipType(context, item, relationshipType, isLeft, limit, offset);
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findByRelationshipType(Context context, RelationshipType relationshipType)
|
|
throws SQLException {
|
|
|
|
return findByRelationshipType(context, relationshipType, -1, -1);
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findByRelationshipType(Context context, RelationshipType relationshipType, Integer limit,
|
|
Integer offset)
|
|
throws SQLException {
|
|
return relationshipDAO.findByRelationshipType(context, relationshipType, limit, offset);
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findByTypeName(Context context, String typeName)
|
|
throws SQLException {
|
|
return this.findByTypeName(context, typeName, -1, -1);
|
|
}
|
|
|
|
@Override
|
|
public List<Relationship> findByTypeName(Context context, String typeName, Integer limit, Integer offset)
|
|
throws SQLException {
|
|
return relationshipDAO.findByTypeName(context, typeName, limit, offset);
|
|
}
|
|
|
|
|
|
@Override
|
|
public int countTotal(Context context) throws SQLException {
|
|
return relationshipDAO.countRows(context);
|
|
}
|
|
|
|
@Override
|
|
public int countByItem(Context context, Item item) throws SQLException {
|
|
return relationshipDAO.countByItem(context, item);
|
|
}
|
|
|
|
@Override
|
|
public int countByRelationshipType(Context context, RelationshipType relationshipType) throws SQLException {
|
|
return relationshipDAO.countByRelationshipType(context, relationshipType);
|
|
}
|
|
|
|
@Override
|
|
public int countByItemAndRelationshipType(Context context, Item item, RelationshipType relationshipType)
|
|
throws SQLException {
|
|
return relationshipDAO.countByItemAndRelationshipType(context, item, relationshipType);
|
|
}
|
|
|
|
@Override
|
|
public int countByTypeName(Context context, String typeName)
|
|
throws SQLException {
|
|
return relationshipDAO.countByTypeName(context, typeName);
|
|
}
|
|
}
|