Implements #23000
This commit is contained in:
parent
c8ad2a1004
commit
6957fe0ea6
|
@ -0,0 +1,28 @@
|
||||||
|
package org.gcube.application.geoportal.common.model.document;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.*;
|
||||||
|
import org.gcube.application.geoportal.common.model.document.accounting.AccountingInfo;
|
||||||
|
import org.gcube.application.geoportal.common.model.document.accounting.User;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class Lock {
|
||||||
|
|
||||||
|
public static final String ID="_id";
|
||||||
|
public static final String INFO="_info";
|
||||||
|
public static final String OPERATION="_operation";
|
||||||
|
|
||||||
|
@JsonProperty(INFO)
|
||||||
|
private AccountingInfo info;
|
||||||
|
@JsonProperty(ID)
|
||||||
|
private String id;
|
||||||
|
@JsonProperty(OPERATION)
|
||||||
|
private String operation;
|
||||||
|
|
||||||
|
}
|
|
@ -8,6 +8,9 @@ import org.gcube.application.geoportal.common.model.document.accounting.Publicat
|
||||||
import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation;
|
import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation;
|
||||||
import org.gcube.application.geoportal.common.model.document.temporal.TemporalReference;
|
import org.gcube.application.geoportal.common.model.document.temporal.TemporalReference;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@ -26,6 +29,7 @@ public class Project {
|
||||||
public static final String SPATIAL_REFERENCE="_spatialReference";
|
public static final String SPATIAL_REFERENCE="_spatialReference";
|
||||||
public static final String TEMPORAL_REFERENCE="_temporalReference";
|
public static final String TEMPORAL_REFERENCE="_temporalReference";
|
||||||
public static final String THE_DOCUMENT="_theDocument";
|
public static final String THE_DOCUMENT="_theDocument";
|
||||||
|
public static final String LOCK="_lock";
|
||||||
|
|
||||||
// CORE METADATA
|
// CORE METADATA
|
||||||
|
|
||||||
|
@ -59,4 +63,22 @@ public class Project {
|
||||||
|
|
||||||
@JsonProperty(THE_DOCUMENT)
|
@JsonProperty(THE_DOCUMENT)
|
||||||
private Document theDocument;
|
private Document theDocument;
|
||||||
|
|
||||||
|
@JsonProperty(LOCK)
|
||||||
|
private Lock lock;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to equals but without checking following fields
|
||||||
|
*
|
||||||
|
* lock
|
||||||
|
* @param o
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean isEquivalent(Object o) {
|
||||||
|
if (this == o) return true;
|
||||||
|
if (!(o instanceof Project)) return false;
|
||||||
|
Project project = (Project) o;
|
||||||
|
return Objects.equals(getId(), project.getId()) && Objects.equals(getVersion(), project.getVersion()) && Objects.equals(getInfo(), project.getInfo()) && Objects.equals(getProfileID(), project.getProfileID()) && Objects.equals(getProfileVersion(), project.getProfileVersion()) && Objects.equals(getLifecycleInformation(), project.getLifecycleInformation()) && Arrays.equals(getRelationships(), project.getRelationships()) && Objects.equals(getSpatialReference(), project.getSpatialReference()) && Objects.equals(getTemporalReference(), project.getTemporalReference()) && Objects.equals(getTheDocument(), project.getTheDocument());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,9 @@ import org.gcube.application.geoportal.common.model.rest.QueryRequest;
|
||||||
import org.gcube.application.geoportal.common.model.rest.RegisterFileSetRequest;
|
import org.gcube.application.geoportal.common.model.rest.RegisterFileSetRequest;
|
||||||
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
|
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
|
||||||
import org.gcube.application.geoportal.service.model.internal.faults.DeletionException;
|
import org.gcube.application.geoportal.service.model.internal.faults.DeletionException;
|
||||||
|
import org.gcube.application.geoportal.service.model.internal.faults.InvalidLockException;
|
||||||
|
import org.gcube.application.geoportal.service.model.internal.faults.ProjectLockedException;
|
||||||
|
import org.gcube.application.geoportal.service.model.internal.faults.ProjectNotFoundException;
|
||||||
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
|
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -22,7 +25,7 @@ public interface MongoManagerI<T> {
|
||||||
public T registerNew(Document toRegister) throws IOException, StepException, EventException;
|
public T registerNew(Document toRegister) throws IOException, StepException, EventException;
|
||||||
|
|
||||||
// update
|
// update
|
||||||
public T update(String id,Document toSetDocument) throws IOException, StepException, EventException;
|
public T update(String id,Document toSetDocument) throws IOException, StepException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException;
|
||||||
|
|
||||||
// delete
|
// delete
|
||||||
|
|
||||||
|
@ -30,17 +33,17 @@ public interface MongoManagerI<T> {
|
||||||
|
|
||||||
// get By ID
|
// get By ID
|
||||||
|
|
||||||
public T getByID(String id) throws IOException;
|
public T getByID(String id) throws IOException, ProjectNotFoundException;
|
||||||
|
|
||||||
// query
|
// query
|
||||||
|
|
||||||
public Iterable<Document> query(QueryRequest request);
|
public Iterable<Document> query(QueryRequest request);
|
||||||
public Iterable<T> filter(QueryRequest request);
|
public Iterable<T> filter(QueryRequest request);
|
||||||
|
|
||||||
public T performStep(String id, String step, Document options) throws IOException, StepException;
|
public T performStep(String id, String step, Document options) throws IOException, StepException, ProjectLockedException, ProjectNotFoundException, InvalidLockException;
|
||||||
|
|
||||||
public T registerFileSet(String id, RegisterFileSetRequest request) throws ConfigurationException, StorageHubException, StorageException, StepException, JsonProcessingException, DeletionException, EventException;
|
public T registerFileSet(String id, RegisterFileSetRequest request) throws ConfigurationException, StorageHubException, StorageException, StepException, JsonProcessingException, DeletionException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException;
|
||||||
public T deleteFileSet(String id, String destination, Boolean force) throws ConfigurationException, StorageHubException, StorageException, StepException, JsonProcessingException, DeletionException, EventException;
|
public T deleteFileSet(String id, String destination, Boolean force) throws ConfigurationException, StorageHubException, StorageException, StepException, JsonProcessingException, DeletionException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException;
|
||||||
|
|
||||||
public Configuration getConfiguration()throws ConfigurationException;
|
public Configuration getConfiguration()throws ConfigurationException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,12 @@ package org.gcube.application.geoportal.service.engine.mongo;
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.mongodb.client.MongoCollection;
|
import com.mongodb.client.MongoCollection;
|
||||||
import com.mongodb.client.MongoDatabase;
|
import com.mongodb.client.MongoDatabase;
|
||||||
|
import com.mongodb.client.model.FindOneAndReplaceOptions;
|
||||||
|
import com.mongodb.client.model.FindOneAndUpdateOptions;
|
||||||
|
import com.mongodb.client.model.ReturnDocument;
|
||||||
import com.vdurmont.semver4j.Semver;
|
import com.vdurmont.semver4j.Semver;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
import lombok.SneakyThrows;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections.ArrayStack;
|
import org.apache.commons.collections.ArrayStack;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
@ -45,9 +49,8 @@ import org.gcube.application.geoportal.service.engine.WorkspaceManager;
|
||||||
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
|
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
|
||||||
import org.gcube.application.geoportal.service.engine.providers.PluginManager;
|
import org.gcube.application.geoportal.service.engine.providers.PluginManager;
|
||||||
import org.gcube.application.geoportal.service.engine.providers.ProfileMapCache;
|
import org.gcube.application.geoportal.service.engine.providers.ProfileMapCache;
|
||||||
import org.gcube.application.geoportal.service.model.internal.faults.DeletionException;
|
import org.gcube.application.geoportal.service.model.internal.faults.*;
|
||||||
import org.gcube.application.cms.serialization.Serialization;
|
import org.gcube.application.cms.serialization.Serialization;
|
||||||
import org.gcube.application.geoportal.service.model.internal.faults.RegistrationException;
|
|
||||||
import org.gcube.application.geoportal.service.utils.UserUtils;
|
import org.gcube.application.geoportal.service.utils.UserUtils;
|
||||||
import org.gcube.common.storagehub.client.dsl.FolderContainer;
|
import org.gcube.common.storagehub.client.dsl.FolderContainer;
|
||||||
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
|
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
|
||||||
|
@ -56,6 +59,7 @@ import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.lang.invoke.SerializedLambda;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.security.InvalidParameterException;
|
import java.security.InvalidParameterException;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
@ -97,6 +101,71 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
|
||||||
return useCaseDescriptor.getId();
|
return useCaseDescriptor.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected Project lock(String id,String op) throws ProjectNotFoundException, ProjectLockedException, JsonProcessingException {
|
||||||
|
log.trace("Locking {} cause {} ",id,op);
|
||||||
|
|
||||||
|
Lock lock = new Lock();
|
||||||
|
lock.setId(UUID.randomUUID().toString());
|
||||||
|
lock.setInfo(UserUtils.getCurrent().asInfo());
|
||||||
|
lock.setOperation(op);
|
||||||
|
|
||||||
|
// find one and update
|
||||||
|
// filter : id, lock == null
|
||||||
|
// update with new Lock object
|
||||||
|
Document filter = new Document(mongoIDFieldName(),asId(id)).append("$or",Arrays.asList(
|
||||||
|
new Document(Project.LOCK,new Document("$exists",false)),
|
||||||
|
new Document(Project.LOCK,new Document("$type","null"))));
|
||||||
|
log.debug("Lock filter is {} ",filter.toJson());
|
||||||
|
Object obj = getCollection().findOneAndUpdate(
|
||||||
|
// filter by id and missing lock
|
||||||
|
filter,
|
||||||
|
// update lock info
|
||||||
|
new Document("$set",new Document(Project.LOCK, Serialization.asDocument(lock))),
|
||||||
|
new FindOneAndUpdateOptions().returnDocument(ReturnDocument.AFTER)
|
||||||
|
);
|
||||||
|
|
||||||
|
if(obj == null){
|
||||||
|
// unable to lock, verify cause
|
||||||
|
Project p=getByID(id);
|
||||||
|
if(p.getLock()!=null) throw new ProjectLockedException("Project already locked : "+p.getLock());
|
||||||
|
else {
|
||||||
|
log.error("Unable to lock {} ",id);
|
||||||
|
log.debug("Existing project is {} ",p);
|
||||||
|
throw new RuntimeException("Unable to lock unlocked project "+id);
|
||||||
|
}
|
||||||
|
} else return Serialization.convert(obj,Project.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Project unlockAndUpdate(Project proj) throws InvalidLockException, ProjectNotFoundException, JsonProcessingException {
|
||||||
|
log.trace("Unlocking {} lock is {} ",proj.getId(),proj.getLock());
|
||||||
|
// find one and update
|
||||||
|
Lock oldLock = proj.getLock();
|
||||||
|
proj.setLock(null);
|
||||||
|
|
||||||
|
Document filter = new Document(mongoIDFieldName(),asId(proj.getId())).append(Project.LOCK+"."+Lock.ID,oldLock.getId());
|
||||||
|
|
||||||
|
Object obj = getCollection().findOneAndReplace(
|
||||||
|
// filter by id and missing lock
|
||||||
|
filter,
|
||||||
|
// update lock info
|
||||||
|
asDocumentWithId(proj),
|
||||||
|
new FindOneAndReplaceOptions().returnDocument(ReturnDocument.AFTER));
|
||||||
|
|
||||||
|
if(obj== null){
|
||||||
|
// can-t unlock, check cause
|
||||||
|
Project p = getByID(proj.getId());
|
||||||
|
throw new InvalidLockException("Found lock for "+p.getId()+" is "+p.getLock()+", expected is "+oldLock);
|
||||||
|
}return Serialization.convert(obj,Project.class);
|
||||||
|
|
||||||
|
// filter : id, lock id
|
||||||
|
// update with project (NB without lock)
|
||||||
|
// if none matched
|
||||||
|
// not found if proj id non existent
|
||||||
|
// else invalid lock
|
||||||
|
// return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Getter(lazy = true)
|
@Getter(lazy = true)
|
||||||
private final LifecycleManager manager=getLCManager();
|
private final LifecycleManager manager=getLCManager();
|
||||||
|
|
||||||
|
@ -163,20 +232,24 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
|
||||||
ObjectId id =insertDoc(asDocumentWithId(toRegister));
|
ObjectId id =insertDoc(asDocumentWithId(toRegister));
|
||||||
|
|
||||||
log.info("Obtained id {} ",id);
|
log.info("Obtained id {} ",id);
|
||||||
return getByID(id.toHexString());
|
try {
|
||||||
|
return getByID(id.toHexString());
|
||||||
|
}catch (ProjectNotFoundException e){
|
||||||
|
throw new WebApplicationException("Unexpected exception while registering project ",e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Project update(String id, Document toSet) throws IOException, EventException {
|
public Project update(String id, Document toSet) throws IOException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException {
|
||||||
log.trace("Replacing {} ",toSet);
|
log.trace("Replacing {} ",toSet);
|
||||||
Project toUpdate=getByID(id);
|
Project toUpdate=lock(id,"Manual update");
|
||||||
toUpdate.setTheDocument(toSet);
|
try {
|
||||||
toUpdate.getLifecycleInformation().cleanState();
|
toUpdate.setTheDocument(toSet);
|
||||||
|
toUpdate.getLifecycleInformation().cleanState();
|
||||||
toUpdate=onUpdate(toUpdate);
|
toUpdate = onUpdate(toUpdate);
|
||||||
Project toReturn =convert(replaceDoc(asDocumentWithId(toUpdate),new ObjectId(id)), Project.class);
|
}finally{
|
||||||
log.debug("Updated Project is {}",toReturn);
|
return unlockAndUpdate(toUpdate);
|
||||||
return toReturn;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -192,7 +265,7 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
|
||||||
public void delete(String id,boolean force) throws DeletionException {
|
public void delete(String id,boolean force) throws DeletionException {
|
||||||
log.debug("Deleting by ID {}, force {}",id,force);
|
log.debug("Deleting by ID {}, force {}",id,force);
|
||||||
try{
|
try{
|
||||||
Project doc =getByID(id);
|
Project doc =lock(id,"Deletion { force : "+force+"}");
|
||||||
|
|
||||||
// TODO INVOKE LIFECYCLE
|
// TODO INVOKE LIFECYCLE
|
||||||
|
|
||||||
|
@ -218,9 +291,9 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Project getByID(String id) throws WebApplicationException{
|
public Project getByID(String id) throws ProjectNotFoundException{
|
||||||
Document doc=getDocById(asId(id));
|
Document doc=getDocById(asId(id));
|
||||||
if(doc==null) throw new WebApplicationException("No document with ID "+id);
|
if(doc==null) throw new ProjectNotFoundException("No document with ID "+id);
|
||||||
return convert(doc, Project.class);
|
return convert(doc, Project.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,8 +323,8 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Project performStep(String id, String step, Document options) throws StepException, JsonProcessingException {
|
public Project performStep(String id, String step, Document options) throws StepException, JsonProcessingException, ProjectLockedException, ProjectNotFoundException, InvalidLockException {
|
||||||
Project document = getByID(id);
|
Project document = lock(id,"Step "+step+" execution");
|
||||||
try{
|
try{
|
||||||
document.getLifecycleInformation().cleanState();
|
document.getLifecycleInformation().cleanState();
|
||||||
document = step(document, step, options);
|
document = step(document, step, options);
|
||||||
|
@ -268,7 +341,7 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
|
||||||
step,document.getLifecycleInformation().getLastOperationStatus());
|
step,document.getLifecycleInformation().getLastOperationStatus());
|
||||||
log.debug("LifecycleInformation is {} ",document.getLifecycleInformation());
|
log.debug("LifecycleInformation is {} ",document.getLifecycleInformation());
|
||||||
if(log.isTraceEnabled())log.trace("Document is {} ",Serialization.write(document));
|
if(log.isTraceEnabled())log.trace("Document is {} ",Serialization.write(document));
|
||||||
return convert(replaceDoc(asDocumentWithId(document),new ObjectId(id)), Project.class);
|
return unlockAndUpdate(document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,103 +360,119 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Project registerFileSet(String id, RegisterFileSetRequest request) throws ConfigurationException, StorageHubException, StorageException, StepException, JsonProcessingException, DeletionException, EventException {
|
public Project registerFileSet(String id, RegisterFileSetRequest request) throws ConfigurationException, StorageHubException, StorageException, StepException, JsonProcessingException, DeletionException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException {
|
||||||
log.info("Registering Fileset for {} [useCaseDescriptor ID {}], Request is {} ",id, useCaseDescriptor.getId(),request);
|
log.info("Registering Fileset for {} [useCaseDescriptor ID {}], Request is {} ",id, useCaseDescriptor.getId(),request);
|
||||||
|
|
||||||
List<TempFile> files=request.getStreams();
|
List<TempFile> files=request.getStreams();
|
||||||
Document attributes =request.getAttributes();
|
Document attributes =request.getAttributes();
|
||||||
Project doc=getByID(id);
|
Project doc=lock(id,"Register Fileset");
|
||||||
doc.getLifecycleInformation().cleanState();
|
try {
|
||||||
doc.getLifecycleInformation().setLastOperationStatus(LifecycleInformation.Status.OK);
|
doc.getLifecycleInformation().cleanState();
|
||||||
|
doc.getLifecycleInformation().setLastOperationStatus(LifecycleInformation.Status.OK);
|
||||||
|
|
||||||
WorkspaceManager ws=new WorkspaceManager();
|
WorkspaceManager ws = new WorkspaceManager();
|
||||||
StorageUtils storage=ImplementationProvider.get().getEngineByManagedClass(StorageUtils.class);
|
StorageUtils storage = ImplementationProvider.get().getEngineByManagedClass(StorageUtils.class);
|
||||||
|
|
||||||
|
|
||||||
log.debug("Checking field {} definition in {}",request.getFieldDefinitionPath(), useCaseDescriptor.getId());
|
log.debug("Checking field {} definition in {}", request.getFieldDefinitionPath(), useCaseDescriptor.getId());
|
||||||
Field fieldDefinition=getFieldDefinition(useCaseDescriptor,request.getFieldDefinitionPath());
|
Field fieldDefinition = getFieldDefinition(useCaseDescriptor, request.getFieldDefinitionPath());
|
||||||
|
|
||||||
JSONPathWrapper docWrapper=new JSONPathWrapper(doc.getTheDocument().toJson());
|
JSONPathWrapper docWrapper = new JSONPathWrapper(doc.getTheDocument().toJson());
|
||||||
|
|
||||||
List<String> matchingPaths = docWrapper.getMatchingPaths(request.getParentPath());
|
List<String> matchingPaths = docWrapper.getMatchingPaths(request.getParentPath());
|
||||||
if(matchingPaths.size()>1) throw new WebApplicationException("Multiple Destination matching parent path "+request.getParentPath(),Response.Status.BAD_REQUEST);
|
if (matchingPaths.size() > 1)
|
||||||
if(matchingPaths.isEmpty()) throw new WebApplicationException("PArent path not found at "+request.getParentPath(),Response.Status.BAD_REQUEST);
|
throw new WebApplicationException("Multiple Destination matching parent path " + request.getParentPath(), Response.Status.BAD_REQUEST);
|
||||||
|
if (matchingPaths.isEmpty())
|
||||||
|
throw new WebApplicationException("PArent path not found at " + request.getParentPath(), Response.Status.BAD_REQUEST);
|
||||||
|
|
||||||
String parentMatchingPath = matchingPaths.get(0);
|
String parentMatchingPath = matchingPaths.get(0);
|
||||||
List<Object> foundElementsByMatchingPaths = docWrapper.getByPath(parentMatchingPath);
|
List<Object> foundElementsByMatchingPaths = docWrapper.getByPath(parentMatchingPath);
|
||||||
if(foundElementsByMatchingPaths == null || foundElementsByMatchingPaths.isEmpty())
|
if (foundElementsByMatchingPaths == null || foundElementsByMatchingPaths.isEmpty())
|
||||||
throw new WebApplicationException("No element found at "+ parentMatchingPath,Response.Status.BAD_REQUEST);
|
throw new WebApplicationException("No element found at " + parentMatchingPath, Response.Status.BAD_REQUEST);
|
||||||
|
|
||||||
Document parent = Serialization.asDocument(foundElementsByMatchingPaths.get(0));
|
Document parent = Serialization.asDocument(foundElementsByMatchingPaths.get(0));
|
||||||
|
|
||||||
|
|
||||||
// PREPARE REGISTERED FS
|
// PREPARE REGISTERED FS
|
||||||
|
|
||||||
// MANAGE CLASH
|
// MANAGE CLASH
|
||||||
switch (request.getClashOption()){
|
switch (request.getClashOption()) {
|
||||||
case REPLACE_EXISTING: {
|
case REPLACE_EXISTING: {
|
||||||
if(fieldDefinition.isCollection())
|
if (fieldDefinition.isCollection())
|
||||||
throw new WebApplicationException("Cannot replace repeatable field "+request.getFieldDefinitionPath()+".",Response.Status.BAD_REQUEST);
|
throw new WebApplicationException("Cannot replace repeatable field " + request.getFieldDefinitionPath() + ".", Response.Status.BAD_REQUEST);
|
||||||
// DELETE EXISTING AND PUT
|
// DELETE EXISTING AND PUT
|
||||||
RegisteredFileSet toDelete = Serialization.convert(parent.get(request.getFieldName()),RegisteredFileSet.class);
|
RegisteredFileSet toDelete = Serialization.convert(parent.get(request.getFieldName()), RegisteredFileSet.class);
|
||||||
if(!(toDelete == null)&&!(toDelete.isEmpty()))
|
if (!(toDelete == null) && !(toDelete.isEmpty()))
|
||||||
deleteFileSetRoutine(toDelete,false,ws);
|
deleteFileSetRoutine(toDelete, false, ws);
|
||||||
|
|
||||||
RegisteredFileSet fs = prepareRegisteredFileSet(doc.getInfo(),doc.getId(), useCaseDescriptor.getId(), request.getAttributes(),files,storage,ws);
|
RegisteredFileSet fs = prepareRegisteredFileSet(doc.getInfo(), doc.getId(), useCaseDescriptor.getId(), request.getAttributes(), files, storage, ws);
|
||||||
log.debug("Registered Fileset for [ID {} useCaseDescriptor {}] is {} ",fs,doc.getId(),doc.getProfileID());
|
log.debug("Registered Fileset for [ID {} useCaseDescriptor {}] is {} ", fs, doc.getId(), doc.getProfileID());
|
||||||
docWrapper.putElement(parentMatchingPath,request.getFieldName(),fs);
|
docWrapper.putElement(parentMatchingPath, request.getFieldName(), fs);
|
||||||
break;}
|
break;
|
||||||
|
}
|
||||||
case MERGE_EXISTING: {
|
case MERGE_EXISTING: {
|
||||||
if(fieldDefinition.isCollection())
|
if (fieldDefinition.isCollection())
|
||||||
throw new WebApplicationException("Cannot merge repeatable field "+request.getFieldDefinitionPath()+".",Response.Status.BAD_REQUEST);
|
throw new WebApplicationException("Cannot merge repeatable field " + request.getFieldDefinitionPath() + ".", Response.Status.BAD_REQUEST);
|
||||||
RegisteredFileSet original = Serialization.convert(parent.get(request.getFieldName()),RegisteredFileSet.class);
|
RegisteredFileSet original = Serialization.convert(parent.get(request.getFieldName()), RegisteredFileSet.class);
|
||||||
// MERGE ATTRIBUTES AND PUT
|
// MERGE ATTRIBUTES AND PUT
|
||||||
Document toUseAttributes=request.getAttributes();
|
Document toUseAttributes = request.getAttributes();
|
||||||
if(original!=null) toUseAttributes.putAll(original);
|
if (original != null) toUseAttributes.putAll(original);
|
||||||
RegisteredFileSet fs = prepareRegisteredFileSet(doc.getInfo(),doc.getId(), useCaseDescriptor.getId(), toUseAttributes,files,storage,ws);
|
RegisteredFileSet fs = prepareRegisteredFileSet(doc.getInfo(), doc.getId(), useCaseDescriptor.getId(), toUseAttributes, files, storage, ws);
|
||||||
log.debug("Registered Fileset for [ID {} useCaseDescriptor {}] is {} ",fs,doc.getId(),doc.getProfileID());
|
log.debug("Registered Fileset for [ID {} useCaseDescriptor {}] is {} ", fs, doc.getId(), doc.getProfileID());
|
||||||
docWrapper.putElement(parentMatchingPath,request.getFieldName(),fs);
|
docWrapper.putElement(parentMatchingPath, request.getFieldName(), fs);
|
||||||
break;}
|
break;
|
||||||
|
}
|
||||||
case APPEND: {
|
case APPEND: {
|
||||||
if(!fieldDefinition.isCollection())
|
if (!fieldDefinition.isCollection())
|
||||||
throw new WebApplicationException("Cannot add to single field "+request.getFieldDefinitionPath()+".",Response.Status.BAD_REQUEST);
|
throw new WebApplicationException("Cannot add to single field " + request.getFieldDefinitionPath() + ".", Response.Status.BAD_REQUEST);
|
||||||
RegisteredFileSet fs = prepareRegisteredFileSet(doc.getInfo(),doc.getId(), useCaseDescriptor.getId(), request.getAttributes(),files,storage,ws);
|
RegisteredFileSet fs = prepareRegisteredFileSet(doc.getInfo(), doc.getId(), useCaseDescriptor.getId(), request.getAttributes(), files, storage, ws);
|
||||||
log.debug("Registered Fileset for [ID {} useCaseDescriptor {}] is {} ",fs,doc.getId(),doc.getProfileID());
|
log.debug("Registered Fileset for [ID {} useCaseDescriptor {}] is {} ", fs, doc.getId(), doc.getProfileID());
|
||||||
|
|
||||||
docWrapper.addElementToArray(String.format("%1ds['%2$s']",parentMatchingPath,request.getFieldName()),fs);
|
docWrapper.addElementToArray(String.format("%1ds['%2$s']", parentMatchingPath, request.getFieldName()), fs);
|
||||||
break;}
|
break;
|
||||||
default: {throw new WebApplicationException("Unexpected clash policy "+request.getClashOption(),Response.Status.BAD_REQUEST);}
|
}
|
||||||
|
default: {
|
||||||
|
throw new WebApplicationException("Unexpected clash policy " + request.getClashOption(), Response.Status.BAD_REQUEST);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
log.debug("Setting result on profiled document");
|
log.debug("Setting result on profiled document");
|
||||||
doc.setTheDocument(Document.parse(docWrapper.getValueCTX().jsonString()));
|
doc.setTheDocument(Document.parse(docWrapper.getValueCTX().jsonString()));
|
||||||
|
|
||||||
doc=onUpdate(doc);
|
doc = onUpdate(doc);
|
||||||
|
}finally {
|
||||||
return convert(replaceDoc(asDocumentWithId(doc),new ObjectId(id)), Project.class);
|
return unlockAndUpdate(doc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Project deleteFileSet(String id, String path, Boolean force) throws ConfigurationException, StorageHubException, JsonProcessingException, DeletionException, EventException {
|
public Project deleteFileSet(String id, String path, Boolean force) throws ConfigurationException, StorageHubException, JsonProcessingException, DeletionException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException {
|
||||||
log.info("Deleting Fileset for {} [useCaseDescriptor ID {}], at {} [force {} ]",id, useCaseDescriptor.getId(),path,force);
|
log.info("Deleting Fileset for {} [useCaseDescriptor ID {}], at {} [force {} ]",id, useCaseDescriptor.getId(),path,force);
|
||||||
|
|
||||||
Project doc = getByID(id);
|
Project doc = lock(id,"Fileset Deletion");
|
||||||
doc.getLifecycleInformation().cleanState();
|
|
||||||
doc.getLifecycleInformation().cleanState().setLastOperationStatus(LifecycleInformation.Status.OK);
|
try {
|
||||||
|
doc.getLifecycleInformation().cleanState();
|
||||||
|
doc.getLifecycleInformation().cleanState().setLastOperationStatus(LifecycleInformation.Status.OK);
|
||||||
|
|
||||||
|
|
||||||
JSONPathWrapper wrapper = new JSONPathWrapper(doc.getTheDocument().toJson());
|
JSONPathWrapper wrapper = new JSONPathWrapper(doc.getTheDocument().toJson());
|
||||||
List<String> matchingPaths=wrapper.getMatchingPaths(path);
|
List<String> matchingPaths = wrapper.getMatchingPaths(path);
|
||||||
if(matchingPaths.isEmpty()) throw new WebApplicationException("No Registered FileSet found at "+path,Response.Status.BAD_REQUEST);
|
if (matchingPaths.isEmpty())
|
||||||
if(matchingPaths.size()>1) throw new WebApplicationException("Multiple Fileset ("+matchingPaths.size()+") matching "+path,Response.Status.BAD_REQUEST);
|
throw new WebApplicationException("No Registered FileSet found at " + path, Response.Status.BAD_REQUEST);
|
||||||
RegisteredFileSet fs = Serialization.convert(wrapper.getByPath(path),RegisteredFileSet.class);
|
if (matchingPaths.size() > 1)
|
||||||
log.debug("Going to delete {}",fs);
|
throw new WebApplicationException("Multiple Fileset (" + matchingPaths.size() + ") matching " + path, Response.Status.BAD_REQUEST);
|
||||||
deleteFileSetRoutine(fs,force,new WorkspaceManager());
|
RegisteredFileSet fs = Serialization.convert(wrapper.getByPath(path), RegisteredFileSet.class);
|
||||||
log.debug("Removing FS from document [ID : ] by path {}",id,path);
|
log.debug("Going to delete {}", fs);
|
||||||
wrapper.setElement(path,null);
|
deleteFileSetRoutine(fs, force, new WorkspaceManager());
|
||||||
doc=onUpdate(doc);
|
log.debug("Removing FS from document [ID : ] by path {}", id, path);
|
||||||
return convert(replaceDoc(asDocumentWithId(doc),new ObjectId(id)), Project.class);
|
wrapper.setElement(path, null);
|
||||||
|
doc = onUpdate(doc);
|
||||||
|
}finally {
|
||||||
|
return unlockAndUpdate(doc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -477,19 +566,19 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Project triggerEvent(Project theDocument, String event, Document parameters) {
|
private Project triggerEvent(Project project, String event, Document parameters) {
|
||||||
try{
|
try{
|
||||||
log.info("[UseCaseDescriptor {}] triggering event {} on {}" , useCaseDescriptor.getId(),event,getManager().getDescriptor());
|
log.info("[UseCaseDescriptor {}] triggering event {} on {}" , useCaseDescriptor.getId(),event,getManager().getDescriptor());
|
||||||
AccountingInfo user= UserUtils.getCurrent().asInfo();
|
AccountingInfo user= UserUtils.getCurrent().asInfo();
|
||||||
EventExecutionRequest request= new EventExecutionRequest(useCaseDescriptor,user.getUser(),user.getContext(),theDocument,event);
|
EventExecutionRequest request= new EventExecutionRequest(useCaseDescriptor,user.getUser(),user.getContext(),project,event);
|
||||||
log.debug("Triggering {}",request);
|
log.debug("Triggering {}",request);
|
||||||
DocumentHandlingReport report = getManager().onEvent(request);
|
DocumentHandlingReport report = getManager().onEvent(request);
|
||||||
return report.prepareResult();
|
return report.prepareResult();
|
||||||
} catch (Throwable t){
|
} catch (Throwable t){
|
||||||
log.error("Unable to trigger event "+event,t);
|
log.error("Unable to trigger event "+event,t);
|
||||||
theDocument.getLifecycleInformation().addErrorMessage("Unable to trigger "+event+" cause : "+ t.getMessage());
|
project.getLifecycleInformation().addErrorMessage("Unable to trigger "+event+" cause : "+ t.getMessage());
|
||||||
theDocument.getLifecycleInformation().setLastOperationStatus(LifecycleInformation.Status.ERROR);
|
project.getLifecycleInformation().setLastOperationStatus(LifecycleInformation.Status.ERROR);
|
||||||
return theDocument;
|
return project;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.gcube.application.geoportal.service.model.internal.faults;
|
||||||
|
|
||||||
|
public class InvalidLockException extends Exception{
|
||||||
|
public InvalidLockException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidLockException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidLockException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidLockException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidLockException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.gcube.application.geoportal.service.model.internal.faults;
|
||||||
|
|
||||||
|
public class ProjectLockedException extends Exception{
|
||||||
|
public ProjectLockedException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectLockedException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectLockedException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectLockedException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectLockedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package org.gcube.application.geoportal.service.model.internal.faults;
|
||||||
|
|
||||||
|
public class ProjectNotFoundException extends Exception {
|
||||||
|
public ProjectNotFoundException() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectNotFoundException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectNotFoundException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectNotFoundException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProjectNotFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,9 @@
|
||||||
package org.gcube.application.geoportal.service.rest;
|
package org.gcube.application.geoportal.service.rest;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.gcube.application.geoportal.service.model.internal.faults.InvalidLockException;
|
||||||
|
import org.gcube.application.geoportal.service.model.internal.faults.ProjectLockedException;
|
||||||
|
import org.gcube.application.geoportal.service.model.internal.faults.ProjectNotFoundException;
|
||||||
|
|
||||||
import javax.ws.rs.WebApplicationException;
|
import javax.ws.rs.WebApplicationException;
|
||||||
import javax.ws.rs.core.Response.Status;
|
import javax.ws.rs.core.Response.Status;
|
||||||
|
@ -32,8 +35,15 @@ public abstract class GuardedMethod<T> {
|
||||||
result=run();
|
result=run();
|
||||||
return this;
|
return this;
|
||||||
}catch(WebApplicationException e) {
|
}catch(WebApplicationException e) {
|
||||||
log.error("Throwing Web Application Exception ",e);
|
log.error("Throwing Web Application Exception ", e);
|
||||||
throw e;
|
throw e;
|
||||||
|
}catch(ProjectNotFoundException e){
|
||||||
|
throw new WebApplicationException("Project not found", e,Status.NOT_FOUND);
|
||||||
|
}catch(ProjectLockedException e){
|
||||||
|
throw new WebApplicationException("Project is currently locked", e,Status.PRECONDITION_FAILED);
|
||||||
|
}catch(InvalidLockException e){
|
||||||
|
log.error("Lock exception ",e);
|
||||||
|
throw new WebApplicationException("Conflicts found in locks", e,Status.CONFLICT);
|
||||||
}catch(Throwable t) {
|
}catch(Throwable t) {
|
||||||
log.error("Unexpected error ",t);
|
log.error("Unexpected error ",t);
|
||||||
throw new WebApplicationException("Unexpected internal error", t,Status.INTERNAL_SERVER_ERROR);
|
throw new WebApplicationException("Unexpected internal error", t,Status.INTERNAL_SERVER_ERROR);
|
||||||
|
|
Loading…
Reference in New Issue