mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-17 23:13:10 +00:00
D4CRIS-416 introduce model class to manage patch operation deserialization
This commit is contained in:
@@ -23,6 +23,7 @@ import org.apache.commons.collections4.CollectionUtils;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.atteo.evo.inflector.English;
|
import org.atteo.evo.inflector.English;
|
||||||
|
import org.dspace.app.rest.converter.JsonPatchConverter;
|
||||||
import org.dspace.app.rest.exception.PaginationException;
|
import org.dspace.app.rest.exception.PaginationException;
|
||||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||||
import org.dspace.app.rest.exception.PatchUnprocessableEntityException;
|
import org.dspace.app.rest.exception.PatchUnprocessableEntityException;
|
||||||
@@ -35,6 +36,7 @@ import org.dspace.app.rest.model.LinkRest;
|
|||||||
import org.dspace.app.rest.model.RestModel;
|
import org.dspace.app.rest.model.RestModel;
|
||||||
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
||||||
import org.dspace.app.rest.model.hateoas.EmbeddedPage;
|
import org.dspace.app.rest.model.hateoas.EmbeddedPage;
|
||||||
|
import org.dspace.app.rest.model.patch.Patch;
|
||||||
import org.dspace.app.rest.model.step.UploadStatusResponse;
|
import org.dspace.app.rest.model.step.UploadStatusResponse;
|
||||||
import org.dspace.app.rest.repository.DSpaceRestRepository;
|
import org.dspace.app.rest.repository.DSpaceRestRepository;
|
||||||
import org.dspace.app.rest.repository.LinkRestRepository;
|
import org.dspace.app.rest.repository.LinkRestRepository;
|
||||||
@@ -49,8 +51,6 @@ import org.springframework.data.domain.Sort;
|
|||||||
import org.springframework.data.rest.webmvc.ControllerUtils;
|
import org.springframework.data.rest.webmvc.ControllerUtils;
|
||||||
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
|
import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler;
|
||||||
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
import org.springframework.data.rest.webmvc.ResourceNotFoundException;
|
||||||
import org.springframework.data.rest.webmvc.json.patch.JsonPatchPatchConverter;
|
|
||||||
import org.springframework.data.rest.webmvc.json.patch.Patch;
|
|
||||||
import org.springframework.data.web.PagedResourcesAssembler;
|
import org.springframework.data.web.PagedResourcesAssembler;
|
||||||
import org.springframework.hateoas.Link;
|
import org.springframework.hateoas.Link;
|
||||||
import org.springframework.hateoas.PagedResources;
|
import org.springframework.hateoas.PagedResources;
|
||||||
@@ -263,7 +263,7 @@ public class RestResourceController implements InitializingBean {
|
|||||||
DSpaceRestRepository<DirectlyAddressableRestModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
DSpaceRestRepository<DirectlyAddressableRestModel, ID> repository = utils.getResourceRepository(apiCategory, model);
|
||||||
DirectlyAddressableRestModel modelObject = null;
|
DirectlyAddressableRestModel modelObject = null;
|
||||||
try {
|
try {
|
||||||
JsonPatchPatchConverter patchConverter = new JsonPatchPatchConverter(mapper);
|
JsonPatchConverter patchConverter = new JsonPatchConverter(mapper);
|
||||||
Patch patch = patchConverter.convert(jsonNode);
|
Patch patch = patchConverter.convert(jsonNode);
|
||||||
modelObject = repository.patch(request, apiCategory, model, id, patch);
|
modelObject = repository.patch(request, apiCategory, model, id, patch);
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,154 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.converter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.patch.AddOperation;
|
||||||
|
import org.dspace.app.rest.model.patch.CopyOperation;
|
||||||
|
import org.dspace.app.rest.model.patch.FromOperation;
|
||||||
|
import org.dspace.app.rest.model.patch.JsonValueEvaluator;
|
||||||
|
import org.dspace.app.rest.model.patch.MoveOperation;
|
||||||
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
|
import org.dspace.app.rest.model.patch.Patch;
|
||||||
|
import org.dspace.app.rest.model.patch.RemoveOperation;
|
||||||
|
import org.dspace.app.rest.model.patch.ReplaceOperation;
|
||||||
|
import org.springframework.data.rest.webmvc.json.patch.PatchException;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
|
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
|
||||||
|
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Convert {@link JsonNode}s containing JSON Patch to/from {@link Patch} objects.
|
||||||
|
*
|
||||||
|
* Based on {@link org.springframework.data.rest.webmvc.json.patch.JsonPatchPatchConverter}
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JsonPatchConverter implements PatchConverter<JsonNode> {
|
||||||
|
|
||||||
|
private final @Nonnull ObjectMapper mapper;
|
||||||
|
|
||||||
|
public JsonPatchConverter(ObjectMapper mapper) {
|
||||||
|
this.mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a {@link Patch} object given a JsonNode.
|
||||||
|
*
|
||||||
|
* @param jsonNode a JsonNode containing the JSON Patch
|
||||||
|
* @return a {@link Patch}
|
||||||
|
*/
|
||||||
|
public Patch convert(JsonNode jsonNode) {
|
||||||
|
|
||||||
|
if (!(jsonNode instanceof ArrayNode)) {
|
||||||
|
throw new IllegalArgumentException("JsonNode must be an instance of ArrayNode");
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayNode opNodes = (ArrayNode) jsonNode;
|
||||||
|
List<Operation> ops = new ArrayList<Operation>(opNodes.size());
|
||||||
|
|
||||||
|
for (Iterator<JsonNode> elements = opNodes.elements(); elements.hasNext();) {
|
||||||
|
|
||||||
|
JsonNode opNode = elements.next();
|
||||||
|
|
||||||
|
String opType = opNode.get("op").textValue();
|
||||||
|
String path = opNode.get("path").textValue();
|
||||||
|
|
||||||
|
JsonNode valueNode = opNode.get("value");
|
||||||
|
Object value = valueFromJsonNode(path, valueNode);
|
||||||
|
String from = opNode.has("from") ? opNode.get("from").textValue() : null;
|
||||||
|
|
||||||
|
//IDEA maybe if the operation have a universal name the PatchOperation can be retrieve here not in WorkspaceItemRestRepository.evaluatePatch
|
||||||
|
if (opType.equals("replace")) {
|
||||||
|
ops.add(new ReplaceOperation(path, value));
|
||||||
|
} else if (opType.equals("remove")) {
|
||||||
|
ops.add(new RemoveOperation(path));
|
||||||
|
} else if (opType.equals("add")) {
|
||||||
|
ops.add(new AddOperation(path, value));
|
||||||
|
} else if (opType.equals("copy")) {
|
||||||
|
ops.add(new CopyOperation(path, from));
|
||||||
|
} else if (opType.equals("move")) {
|
||||||
|
ops.add(new MoveOperation(path, from));
|
||||||
|
} else {
|
||||||
|
throw new PatchException("Unrecognized operation type: " + opType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Patch(ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a {@link Patch} as a {@link JsonNode}.
|
||||||
|
*
|
||||||
|
* @param patch the patch
|
||||||
|
* @return a {@link JsonNode} containing JSON Patch.
|
||||||
|
*/
|
||||||
|
public JsonNode convert(Patch patch) {
|
||||||
|
|
||||||
|
List<Operation> operations = patch.getOperations();
|
||||||
|
JsonNodeFactory nodeFactory = JsonNodeFactory.instance;
|
||||||
|
ArrayNode patchNode = nodeFactory.arrayNode();
|
||||||
|
|
||||||
|
for (Operation operation : operations) {
|
||||||
|
|
||||||
|
ObjectNode opNode = nodeFactory.objectNode();
|
||||||
|
opNode.set("op", nodeFactory.textNode(operation.getOp()));
|
||||||
|
opNode.set("path", nodeFactory.textNode(operation.getPath()));
|
||||||
|
|
||||||
|
if (operation instanceof FromOperation) {
|
||||||
|
|
||||||
|
FromOperation fromOp = (FromOperation) operation;
|
||||||
|
opNode.set("from", nodeFactory.textNode(fromOp.getFrom()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = operation.getValue();
|
||||||
|
|
||||||
|
if (value != null) {
|
||||||
|
opNode.set("value", mapper.valueToTree(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
patchNode.add(opNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
return patchNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object valueFromJsonNode(String path, JsonNode valueNode) {
|
||||||
|
|
||||||
|
if (valueNode == null || valueNode.isNull()) {
|
||||||
|
return null;
|
||||||
|
} else if (valueNode.isTextual()) {
|
||||||
|
return valueNode.asText();
|
||||||
|
} else if (valueNode.isFloatingPointNumber()) {
|
||||||
|
return valueNode.asDouble();
|
||||||
|
} else if (valueNode.isBoolean()) {
|
||||||
|
return valueNode.asBoolean();
|
||||||
|
} else if (valueNode.isInt()) {
|
||||||
|
return valueNode.asInt();
|
||||||
|
} else if (valueNode.isLong()) {
|
||||||
|
return valueNode.asLong();
|
||||||
|
} else if (valueNode.isObject() || (valueNode.isArray())) {
|
||||||
|
return new JsonValueEvaluator(mapper, valueNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new PatchException(
|
||||||
|
String.format("Unrecognized valueNode type at path %s and value node %s.", path, valueNode));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,48 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.converter;
|
||||||
|
|
||||||
|
import org.dspace.app.rest.model.patch.Patch;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* A strategy interface for producing {@link Patch} instances from a patch document representation (such as JSON Patch)
|
||||||
|
* and rendering a Patch to a patch document representation. This decouples the {@link Patch} class from any specific
|
||||||
|
* patch format or library that holds the representation.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* For example, if the {@link Patch} is to be represented as JSON Patch, the representation type could be
|
||||||
|
* {@link JsonNode} or some other JSON library's type that holds a JSON document.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Based on {@link org.springframework.data.rest.webmvc.json.patch.PatchConverter}
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public interface PatchConverter<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a patch document representation to a {@link Patch}.
|
||||||
|
*
|
||||||
|
* @param patchRepresentation the representation of a patch.
|
||||||
|
* @return the {@link Patch} object that the document represents.
|
||||||
|
*/
|
||||||
|
Patch convert(T patchRepresentation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a {@link Patch} to a representation object.
|
||||||
|
*
|
||||||
|
* @param patch the {@link Patch} to convert.
|
||||||
|
* @return the patch representation object.
|
||||||
|
*/
|
||||||
|
T convert(Patch patch);
|
||||||
|
}
|
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model.patch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation to track the "add" operation to the given "path".
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class AddOperation extends Operation {
|
||||||
|
|
||||||
|
public AddOperation(String path, Object value) {
|
||||||
|
super("add", path, value);
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model.patch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation to track the "copy" operation to the given "path".
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class CopyOperation extends FromOperation {
|
||||||
|
|
||||||
|
public CopyOperation(String path, String from) {
|
||||||
|
super("copy", path, from);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,36 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model.patch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation to track the "from" operation to the given "path".
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class FromOperation extends Operation {
|
||||||
|
|
||||||
|
private final String from;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the operation
|
||||||
|
*
|
||||||
|
* @param op The name of the operation to perform. (e.g., 'copy')
|
||||||
|
* @param path The operation's target path. (e.g., '/foo/bar/4')
|
||||||
|
* @param from The operation's source path. (e.g., '/foo/bar/5')
|
||||||
|
*/
|
||||||
|
public FromOperation(String op, String path, String from) {
|
||||||
|
super(op, path);
|
||||||
|
this.from = from;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,50 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model.patch;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import org.springframework.data.rest.webmvc.json.patch.LateObjectEvaluator;
|
||||||
|
import org.springframework.data.rest.webmvc.json.patch.PatchException;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link LateObjectEvaluator} implementation that assumes values represented as JSON objects.
|
||||||
|
*
|
||||||
|
* Based on {@link org.springframework.data.rest.webmvc.json.patch.JsonLateObjectEvaluator}
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JsonValueEvaluator implements LateObjectEvaluator {
|
||||||
|
|
||||||
|
private final @Nonnull ObjectMapper mapper;
|
||||||
|
private final @Nonnull JsonNode valueNode;
|
||||||
|
|
||||||
|
public JsonValueEvaluator(ObjectMapper mapper, JsonNode valueNode) {
|
||||||
|
this.mapper = mapper;
|
||||||
|
this.valueNode = valueNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see org.springframework.data.rest.webmvc.json.patch.LateObjectEvaluator#evaluate(java.lang.Class)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> Object evaluate(Class<T> type) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
return mapper.readValue(valueNode.traverse(), type);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new PatchException(String.format("Could not read %s into %s!", valueNode, type), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model.patch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation to track the "move" operation to the given "path".
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MoveOperation extends FromOperation {
|
||||||
|
|
||||||
|
public MoveOperation(String path, String from) {
|
||||||
|
super("move", path, from);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,49 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model.patch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Abstract base class representing and providing support methods for patch operations.
|
||||||
|
*
|
||||||
|
* Based on {@link org.springframework.data.rest.webmvc.json.patch.PatchOperation}
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public abstract class Operation {
|
||||||
|
|
||||||
|
protected String op;
|
||||||
|
protected String path;
|
||||||
|
protected Object value;
|
||||||
|
|
||||||
|
public Operation(String operation, String path) {
|
||||||
|
this.op = operation;
|
||||||
|
this.path = path;
|
||||||
|
this.value = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Operation(String operation, String path, Object value) {
|
||||||
|
this.op = operation;
|
||||||
|
this.path = path;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getOp() {
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model.patch;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* Represents a Patch.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* This class (and {@link Operation} capture the definition of a patch, but are not coupled to any specific patch
|
||||||
|
* representation.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* Based on {@link org.springframework.data.rest.webmvc.json.patch.Patch}
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class Patch {
|
||||||
|
|
||||||
|
private final List<Operation> operations;
|
||||||
|
|
||||||
|
public Patch(List<Operation> operations) {
|
||||||
|
this.operations = operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the number of operations that make up this patch.
|
||||||
|
*/
|
||||||
|
public int size() {
|
||||||
|
return operations.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Operation> getOperations() {
|
||||||
|
return operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model.patch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation to track the "remove" operation to the given "path".
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RemoveOperation extends Operation {
|
||||||
|
|
||||||
|
public RemoveOperation(String path) {
|
||||||
|
super("remove", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,22 @@
|
|||||||
|
/**
|
||||||
|
* The contents of this file are subject to the license and copyright
|
||||||
|
* detailed in the LICENSE and NOTICE files at the root of the source
|
||||||
|
* tree and available online at
|
||||||
|
*
|
||||||
|
* http://www.dspace.org/license/
|
||||||
|
*/
|
||||||
|
package org.dspace.app.rest.model.patch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation to track the "replace" operation to the given "path".
|
||||||
|
*
|
||||||
|
* @author Luigi Andrea Pascarelli (luigiandrea.pascarelli at 4science.it)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ReplaceOperation extends Operation {
|
||||||
|
|
||||||
|
public ReplaceOperation(String path, Object value) {
|
||||||
|
super("replace", path, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -17,6 +17,7 @@ import org.dspace.app.rest.exception.PatchBadRequestException;
|
|||||||
import org.dspace.app.rest.exception.PatchUnprocessableEntityException;
|
import org.dspace.app.rest.exception.PatchUnprocessableEntityException;
|
||||||
import org.dspace.app.rest.model.DirectlyAddressableRestModel;
|
import org.dspace.app.rest.model.DirectlyAddressableRestModel;
|
||||||
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
import org.dspace.app.rest.model.hateoas.DSpaceResource;
|
||||||
|
import org.dspace.app.rest.model.patch.Patch;
|
||||||
import org.dspace.app.rest.model.step.UploadStatusResponse;
|
import org.dspace.app.rest.model.step.UploadStatusResponse;
|
||||||
import org.dspace.app.util.DCInputsReaderException;
|
import org.dspace.app.util.DCInputsReaderException;
|
||||||
import org.dspace.authorize.AuthorizeException;
|
import org.dspace.authorize.AuthorizeException;
|
||||||
@@ -25,7 +26,6 @@ import org.springframework.data.domain.Page;
|
|||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||||
import org.springframework.data.rest.webmvc.json.patch.Patch;
|
|
||||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
@@ -21,6 +21,8 @@ import org.dspace.app.rest.converter.WorkspaceItemConverter;
|
|||||||
import org.dspace.app.rest.exception.PatchBadRequestException;
|
import org.dspace.app.rest.exception.PatchBadRequestException;
|
||||||
import org.dspace.app.rest.model.WorkspaceItemRest;
|
import org.dspace.app.rest.model.WorkspaceItemRest;
|
||||||
import org.dspace.app.rest.model.hateoas.WorkspaceItemResource;
|
import org.dspace.app.rest.model.hateoas.WorkspaceItemResource;
|
||||||
|
import org.dspace.app.rest.model.patch.Operation;
|
||||||
|
import org.dspace.app.rest.model.patch.Patch;
|
||||||
import org.dspace.app.rest.model.step.UploadBitstreamRest;
|
import org.dspace.app.rest.model.step.UploadBitstreamRest;
|
||||||
import org.dspace.app.rest.submit.AbstractRestProcessingStep;
|
import org.dspace.app.rest.submit.AbstractRestProcessingStep;
|
||||||
import org.dspace.app.rest.submit.SubmissionService;
|
import org.dspace.app.rest.submit.SubmissionService;
|
||||||
@@ -49,8 +51,6 @@ import org.springframework.data.domain.Page;
|
|||||||
import org.springframework.data.domain.PageImpl;
|
import org.springframework.data.domain.PageImpl;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.repository.query.Param;
|
import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.data.rest.webmvc.json.patch.Patch;
|
|
||||||
import org.springframework.data.rest.webmvc.json.patch.PatchOperation;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
@@ -242,10 +242,10 @@ public class WorkspaceItemRestRepository extends DSpaceRestRepository<WorkspaceI
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void patch(Context context, HttpServletRequest request, String apiCategory, String model, Integer id, Patch patch) throws SQLException, AuthorizeException {
|
public void patch(Context context, HttpServletRequest request, String apiCategory, String model, Integer id, Patch patch) throws SQLException, AuthorizeException {
|
||||||
List<PatchOperation> operations = patch.getOperations();
|
List<Operation> operations = patch.getOperations();
|
||||||
WorkspaceItemRest wsi = findOne(id);
|
WorkspaceItemRest wsi = findOne(id);
|
||||||
WorkspaceItem source = wis.find(context, id);
|
WorkspaceItem source = wis.find(context, id);
|
||||||
for(PatchOperation op : operations) {
|
for(Operation op : operations) {
|
||||||
//the value in the position 0 is a null value
|
//the value in the position 0 is a null value
|
||||||
String[] path = op.getPath().substring(1).split("/",3);
|
String[] path = op.getPath().substring(1).split("/",3);
|
||||||
if(OPERATION_PATH_SECTIONS.equals(path[0])) {
|
if(OPERATION_PATH_SECTIONS.equals(path[0])) {
|
||||||
|
Reference in New Issue
Block a user