gcube-cms-suite/geoportal-service/src/main/java/org/gcube/application/geoportal/service/engine/mongo/ProfiledMongoManager.java

1030 lines
52 KiB
Java
Raw Normal View History

2021-09-20 16:47:35 +02:00
package org.gcube.application.geoportal.service.engine.mongo;
2021-12-01 11:13:34 +01:00
import com.fasterxml.jackson.core.JsonProcessingException;
2022-03-10 18:15:10 +01:00
import com.mongodb.client.MongoCollection;
2022-03-18 18:35:43 +01:00
import com.mongodb.client.model.FindOneAndReplaceOptions;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReturnDocument;
2022-01-17 18:19:40 +01:00
import com.vdurmont.semver4j.Semver;
2022-01-17 13:30:21 +01:00
import lombok.Getter;
2021-12-01 11:13:34 +01:00
import lombok.extern.slf4j.Slf4j;
2022-01-17 18:19:40 +01:00
import org.apache.commons.io.IOUtils;
2021-12-01 11:13:34 +01:00
import org.bson.Document;
import org.bson.types.ObjectId;
2022-09-26 16:11:20 +02:00
import org.gcube.application.cms.implementations.ImplementationProvider;
import org.gcube.application.cms.implementations.WorkspaceManager;
2022-10-27 16:03:38 +02:00
import org.gcube.application.cms.implementations.faults.*;
2023-01-10 15:57:40 +01:00
import org.gcube.application.cms.implementations.utils.UserUtils;
2021-12-07 16:12:43 +01:00
import org.gcube.application.cms.plugins.LifecycleManager;
2022-02-14 17:06:32 +01:00
import org.gcube.application.cms.plugins.faults.EventException;
2022-03-28 16:35:30 +02:00
import org.gcube.application.cms.plugins.faults.InsufficientPrivileges;
2021-12-07 16:42:39 +01:00
import org.gcube.application.cms.plugins.faults.StepException;
2022-04-08 13:17:52 +02:00
import org.gcube.application.cms.plugins.faults.UnrecognizedStepException;
2022-02-17 16:01:39 +01:00
import org.gcube.application.cms.plugins.reports.DocumentHandlingReport;
2022-02-14 12:23:13 +01:00
import org.gcube.application.cms.plugins.reports.StepExecutionReport;
2022-03-11 18:11:32 +01:00
import org.gcube.application.cms.plugins.requests.BaseRequest;
2022-02-14 17:06:32 +01:00
import org.gcube.application.cms.plugins.requests.EventExecutionRequest;
2021-12-07 16:42:39 +01:00
import org.gcube.application.cms.plugins.requests.StepExecutionRequest;
2022-09-26 16:11:20 +02:00
import org.gcube.application.cms.serialization.Serialization;
2022-01-17 18:19:40 +01:00
import org.gcube.application.geoportal.common.faults.StorageException;
2022-09-26 16:11:20 +02:00
import org.gcube.application.geoportal.common.model.JSONPathWrapper;
2022-03-10 18:15:10 +01:00
import org.gcube.application.geoportal.common.model.configuration.Archive;
2022-09-26 16:11:20 +02:00
import org.gcube.application.geoportal.common.model.configuration.Configuration;
2022-03-11 18:11:32 +01:00
import org.gcube.application.geoportal.common.model.configuration.Index;
2022-09-26 16:11:20 +02:00
import org.gcube.application.geoportal.common.model.document.Lock;
import org.gcube.application.geoportal.common.model.document.Project;
2022-02-14 12:23:13 +01:00
import org.gcube.application.geoportal.common.model.document.access.Access;
import org.gcube.application.geoportal.common.model.document.access.AccessPolicy;
2022-02-14 17:06:32 +01:00
import org.gcube.application.geoportal.common.model.document.accounting.AccountingInfo;
2022-02-14 12:23:13 +01:00
import org.gcube.application.geoportal.common.model.document.accounting.PublicationInfo;
2022-03-24 17:44:00 +01:00
import org.gcube.application.geoportal.common.model.document.accounting.User;
2022-02-14 12:23:13 +01:00
import org.gcube.application.geoportal.common.model.document.filesets.RegisteredFile;
import org.gcube.application.geoportal.common.model.document.filesets.RegisteredFileSet;
2022-02-14 17:06:32 +01:00
import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation;
2022-09-26 16:11:20 +02:00
import org.gcube.application.geoportal.common.model.document.relationships.Relationship;
import org.gcube.application.geoportal.common.model.plugins.LifecycleManagerDescriptor;
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
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.TempFile;
2022-10-25 13:03:14 +02:00
import org.gcube.application.geoportal.common.model.useCaseDescriptor.*;
2022-03-10 18:15:10 +01:00
import org.gcube.application.geoportal.common.utils.ContextUtils;
2022-01-17 18:19:40 +01:00
import org.gcube.application.geoportal.common.utils.StorageUtils;
2022-02-18 18:11:34 +01:00
import org.gcube.application.geoportal.service.engine.providers.PluginManager;
2023-01-10 15:57:40 +01:00
2022-01-17 18:19:40 +01:00
import org.gcube.common.storagehub.client.dsl.FolderContainer;
import org.gcube.common.storagehub.model.exceptions.StorageHubException;
2021-09-20 16:47:35 +02:00
2021-12-07 11:16:26 +01:00
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
2021-12-01 11:13:34 +01:00
import java.io.IOException;
2022-01-17 18:19:40 +01:00
import java.io.InputStream;
import java.net.URL;
2021-12-07 11:16:26 +01:00
import java.security.InvalidParameterException;
2022-03-10 18:15:10 +01:00
import java.time.LocalDateTime;
2022-02-17 16:01:39 +01:00
import java.util.*;
2021-12-01 11:13:34 +01:00
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Consumer;
2022-05-10 10:58:40 +02:00
import java.util.stream.Collectors;
2021-12-01 11:13:34 +01:00
2022-09-26 16:11:20 +02:00
import static org.gcube.application.cms.serialization.Serialization.asDocumentWithId;
import static org.gcube.application.cms.serialization.Serialization.convert;
2021-12-01 11:13:34 +01:00
@Slf4j
2022-03-04 14:23:20 +01:00
public class ProfiledMongoManager extends MongoManager implements MongoManagerI<Project>{
2021-12-01 11:13:34 +01:00
2022-01-18 12:01:33 +01:00
@Getter
2022-03-04 14:23:20 +01:00
UseCaseDescriptor useCaseDescriptor;
2022-03-11 16:42:33 +01:00
2021-12-07 16:12:43 +01:00
2022-03-07 17:59:06 +01:00
@Override
protected String mongoIDFieldName() {
return ID;
}
2021-12-07 11:16:26 +01:00
2023-01-10 15:57:40 +01:00
public ProfiledMongoManager(String profileId) throws ConfigurationException, RegistrationException {
2022-03-04 14:23:20 +01:00
// Check UseCaseDescriptor ID
log.info("Loading useCaseDescriptor ID {} ",profileId);
if(profileId==null) throw new InvalidParameterException("UseCaseDescriptor ID cannot be null");
2022-04-27 19:36:10 +02:00
useCaseDescriptor = ImplementationProvider.get().getProvidedObjectByClass(UCDManagerI.class).getById(profileId);
2022-03-04 18:28:45 +01:00
if(useCaseDescriptor == null )
2022-03-04 14:23:20 +01:00
throw new WebApplicationException("UseCaseDescriptor " + profileId + " not registered", Response.Status.NOT_FOUND);
2021-12-07 16:12:43 +01:00
2022-01-14 12:31:11 +01:00
// Connect to DB
2022-03-11 16:42:33 +01:00
init(getToUseCollectionName());
2022-01-14 12:31:11 +01:00
2022-03-11 16:42:33 +01:00
}
2022-03-04 14:23:20 +01:00
2022-03-11 16:42:33 +01:00
private String getToUseCollectionName(){
//TODO collection name in UCD
return useCaseDescriptor.getId();
2021-12-01 11:13:34 +01:00
}
2022-03-18 18:35:43 +01:00
2022-03-24 17:44:00 +01:00
protected Project lock(String id,String op) throws ProjectNotFoundException, ProjectLockedException, JsonProcessingException, InvalidUserRoleException, UnauthorizedAccess {
2022-03-18 18:35:43 +01:00
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);
}
2022-03-24 17:44:00 +01:00
protected Project unlockAndUpdate(Project proj) throws InvalidLockException, ProjectNotFoundException, JsonProcessingException, InvalidUserRoleException, UnauthorizedAccess {
2022-04-08 15:20:21 +02:00
log.trace("Unlocking for update {} lock is {} ",proj.getId(),proj.getLock());
2022-03-18 18:35:43 +01:00
// 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);
2022-04-08 15:20:21 +02:00
}
2022-03-18 18:35:43 +01:00
2022-04-08 15:20:21 +02:00
protected Project unlock(Project proj) throws InvalidLockException, InvalidUserRoleException, ProjectNotFoundException, UnauthorizedAccess {
log.trace("Unlocking for update {} lock is {} ",proj.getId(),proj.getLock());
// find one and update
Lock oldLock = proj.getLock();
Document filter = new Document(mongoIDFieldName(),asId(proj.getId())).append(Project.LOCK+"."+Lock.ID,oldLock.getId());
Object obj = getCollection().findOneAndUpdate(
// filter by id and missing lock
filter,
// update lock info
new Document("$set",new Document(Project.LOCK, null)),
new FindOneAndUpdateOptions().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);
2022-03-18 18:35:43 +01:00
}
2022-04-08 15:20:21 +02:00
2022-01-17 13:30:21 +01:00
@Getter(lazy = true)
2022-04-08 13:17:52 +02:00
private final LifecycleManager manager=getLCManager();
2021-12-07 16:12:43 +01:00
2022-01-17 13:30:21 +01:00
private LifecycleManager getLCManager() {
try{
LifecycleManager toReturn=null;
2022-03-04 14:23:20 +01:00
//Getting Lifecycle Manager declaration from UseCaseDescriptor
2022-04-01 19:11:11 +02:00
List<HandlerDeclaration> handlerDeclarations= useCaseDescriptor.getHandlersMapByType().get(LifecycleManagerDescriptor.LIFECYCLE_MANAGER_TYPE);
2022-03-04 14:23:20 +01:00
if(handlerDeclarations==null || handlerDeclarations.isEmpty()) throw new ConfigurationException("No Lifecycle Handler defined for useCaseDescriptor ID "+ useCaseDescriptor.getId());
if(handlerDeclarations.size()>1) throw new ConfigurationException("Too many Lifecycle Handlers defined ("+handlerDeclarations+") in useCaseDescriptor ID "+ useCaseDescriptor.getId());
2022-01-17 13:30:21 +01:00
HandlerDeclaration lcHandlerDeclaration=handlerDeclarations.get(0);
// Loading Lifecycle Manager
log.debug("Looking for handler {} ",lcHandlerDeclaration);
2022-02-18 18:11:34 +01:00
toReturn=(LifecycleManager) ImplementationProvider.get().
2022-04-27 19:36:10 +02:00
getProvidedObjectByClass(PluginManager.PluginMap.class).get(lcHandlerDeclaration.getId());
2022-01-17 13:30:21 +01:00
if(toReturn==null) throw new ConfigurationException("Unable to find Lifecycle Manager Plugin. ID "+lcHandlerDeclaration.getId());
return toReturn;
} catch(Throwable t){
log.warn("Unable to load LC Manager ",t);
return null;
}
}
2021-12-07 16:12:43 +01:00
2021-12-01 11:13:34 +01:00
@Override
2022-04-08 15:20:21 +02:00
public Project registerNew(Document toRegisterDoc) throws IOException, InvalidUserRoleException {
2022-03-04 14:23:20 +01:00
log.info("Registering new document in {} ", useCaseDescriptor.getId());
2022-04-01 19:11:11 +02:00
log.trace("Going to register {}",toRegisterDoc.toJson());
User u = UserUtils.getCurrent().asInfo().getUser();
final DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
log.trace("Access policy for user {} is {} ",u,policy);
if(policy == null) {
log.warn("No policy found for {}. Returning empty ", u);
throw new InvalidUserRoleException("No policy defined for current user roles " + u.getRoles());
}
if(policy.getPolicy().getWrite().equals(DataAccessPolicy.Policy.Type.none))
throw new InvalidUserRoleException("User doesn't have write privileges " + u.getRoles());
2021-12-07 16:42:39 +01:00
2022-03-04 14:23:20 +01:00
Project toRegister = new Project();
2021-12-07 11:16:26 +01:00
toRegister.setTheDocument(toRegisterDoc);
2021-12-07 16:42:39 +01:00
PublicationInfo pubInfo=new PublicationInfo();
pubInfo.setCreationInfo(UserUtils.getCurrent().asInfo());
2022-03-04 14:23:20 +01:00
// TODO Set Access From UseCaseDescriptor
2021-12-07 16:42:39 +01:00
Access access=new Access();
access.setLicense("");
access.setPolicy(AccessPolicy.OPEN);
pubInfo.setAccess(access);
2022-05-18 18:24:57 +02:00
2021-12-07 16:42:39 +01:00
toRegister.setInfo(pubInfo);
2021-12-01 11:13:34 +01:00
2022-03-04 14:23:20 +01:00
toRegister.setProfileID(useCaseDescriptor.getId());
toRegister.setProfileVersion(useCaseDescriptor.getVersion());
2022-01-17 18:19:40 +01:00
toRegister.setVersion(new Semver("1.0.0"));
2021-12-01 11:13:34 +01:00
2022-02-14 17:06:32 +01:00
2022-02-17 16:01:39 +01:00
LifecycleInformation draftInfo=new LifecycleInformation().cleanState();
2022-03-29 18:06:09 +02:00
draftInfo.setPhase(LifecycleInformation.CommonPhases.DRAFT_PHASE);
2022-02-17 16:01:39 +01:00
draftInfo.setLastOperationStatus(LifecycleInformation.Status.OK);
2022-02-14 17:06:32 +01:00
toRegister.setLifecycleInformation(draftInfo);
2021-12-01 11:13:34 +01:00
2022-02-17 16:01:39 +01:00
// Apply Lifecycle
toRegister = triggerEvent(toRegister,EventExecutionRequest.Events.ON_INIT_DOCUMENT,null);
2021-12-07 16:42:39 +01:00
log.debug("Going to register {} ",toRegister);
2021-12-01 11:13:34 +01:00
2021-12-15 19:10:19 +01:00
// Insert object
2022-03-11 16:42:33 +01:00
ObjectId id =insertDoc(asDocumentWithId(toRegister));
2021-12-07 16:12:43 +01:00
2021-12-07 16:42:39 +01:00
log.info("Obtained id {} ",id);
2022-03-18 18:35:43 +01:00
try {
return getByID(id.toHexString());
2022-03-24 17:44:00 +01:00
}catch (ProjectNotFoundException | InvalidUserRoleException | UnauthorizedAccess e){
2022-03-18 18:35:43 +01:00
throw new WebApplicationException("Unexpected exception while registering project ",e);
}
2021-12-01 11:13:34 +01:00
}
@Override
2022-03-24 17:44:00 +01:00
public Project update(String id, Document toSet) throws IOException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess {
2021-12-01 11:13:34 +01:00
log.trace("Replacing {} ",toSet);
2022-03-18 18:35:43 +01:00
Project toUpdate=lock(id,"Manual update");
try {
2022-03-24 17:44:00 +01:00
User u = UserUtils.getCurrent().asInfo().getUser();
final DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
log.info("Registering Fileset for {} [{}] , policy for {} is {} ",id,useCaseDescriptor.getId(),u,policy);
if(policy == null) {
log.warn("No policy found for {}. Returning empty ", u);
throw new InvalidUserRoleException("No policy defined for current user roles " + u.getRoles());
}
if(!policy.canWrite(toUpdate,u)) throw new UnauthorizedAccess("No edit rights on project "+id);
2022-03-18 18:35:43 +01:00
toUpdate.setTheDocument(toSet);
toUpdate.getLifecycleInformation().cleanState();
toUpdate = onUpdate(toUpdate);
return unlockAndUpdate(toUpdate);
2022-04-08 15:20:21 +02:00
}catch(Throwable t){
log.error("Unexpected exception ",t);
unlock(toUpdate);
throw t;
2022-03-18 18:35:43 +01:00
}
2022-01-17 18:19:40 +01:00
}
2022-05-10 10:58:40 +02:00
@Override
public Project setRelation(String id, String relation, String targetUCD, String targetId) throws IOException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess, RegistrationException, ConfigurationException {
2022-10-25 13:03:14 +02:00
Project toUpdate=lock(id,"Set Relation "+relation+" toward "+targetUCD+":"+targetId);
2022-05-10 10:58:40 +02:00
try{
2022-10-25 13:03:14 +02:00
log.info(getUseCaseDescriptor().getId()+":"+id+" setting relation "+relation+" toward "+targetUCD+":"+targetId);
// Check if relation is defined
String toSetReverseRelation=null;
List<RelationshipDefinition> existingDefinitions = getUseCaseDescriptor().getRelationshipDefinitions();
for(RelationshipDefinition def : existingDefinitions)
if(def.getId().equals(relation))
toSetReverseRelation =def.getReverseRelationId();
log.debug("{} reverse relation for {} is {}",getUseCaseDescriptor().getId(),relation,toSetReverseRelation);
2022-05-10 10:58:40 +02:00
// check if relation existing
List<Relationship> relations = toUpdate.getRelationshipsByName(relation);
if(!relations.isEmpty()){
// check if targetUCD+targetID already present
List matching = relations.stream().filter(r ->
r.getTargetID().equals(targetId)&&r.getTargetUCD().equals(targetUCD)).collect(Collectors.toList());
if(matching.size()>0) throw new WebApplicationException("Relationship "+relation+" -> "+targetUCD+" : "+targetId+" already set", Response.Status.EXPECTATION_FAILED);
}
// check if target exists
ProfiledMongoManager otherManager = (targetUCD.equals(this.useCaseDescriptor.getId()))?this:new ProfiledMongoManager(targetUCD);
Project other = getByID(targetId);
2022-10-25 13:03:14 +02:00
2022-05-10 10:58:40 +02:00
// add relation
Relationship rel = new Relationship();
rel.setRelationshipName(relation);
rel.setTargetID(targetId);
rel.setTargetUCD(targetUCD);
2022-10-25 13:03:14 +02:00
toUpdate =onUpdate(toUpdate.addRelation(rel));
2022-05-10 10:58:40 +02:00
2022-10-25 13:03:14 +02:00
// set reverse relation
if(toSetReverseRelation!=null){
Relationship reverseRel = new Relationship();
reverseRel.setRelationshipName(toSetReverseRelation);
reverseRel.setTargetID(id);
reverseRel.setTargetUCD(getUseCaseDescriptor().getId());
log.info("Setting reverse relation {} ",reverseRel);
2022-10-25 16:57:41 +02:00
other = otherManager.lock(other.getId(),"Setting reverse relation "+reverseRel);
2022-10-25 13:03:14 +02:00
other.addRelation(reverseRel);
otherManager.unlockAndUpdate(other);
}
2022-09-29 16:33:33 +02:00
return unlockAndUpdate(toUpdate);
2022-05-10 10:58:40 +02:00
}catch(Throwable t){
log.error("Unexpected exception ",t);
unlock(toUpdate);
throw t;
}
}
@Override
public Project deleteRelation(String id, String relation, String targetUCD, String targetId) throws IOException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess, RegistrationException, ConfigurationException {
2022-10-25 13:03:14 +02:00
log.info("Delete relation {}:{}--{}-->{}:{} ",getUseCaseDescriptor().getId(),id,relation,targetUCD,targetId);
2022-09-30 14:57:28 +02:00
Project toUpdate=lock(id,"Delete Relation");
2022-09-30 15:34:35 +02:00
2022-05-10 10:58:40 +02:00
try{
2022-09-30 16:21:55 +02:00
// SET target UCD to present UCD as default
final String toUseTargetUCD = (targetUCD == null || targetUCD.equals(""))? getUseCaseDescriptor().getId():targetUCD;
2022-10-25 13:03:14 +02:00
String toDeleteReverseRelation=null;
List<RelationshipDefinition> existingDefinitions = getUseCaseDescriptor().getRelationshipDefinitions();
for(RelationshipDefinition def : existingDefinitions)
if(def.getId().equals(relation))
toDeleteReverseRelation =def.getReverseRelationId();
log.debug("{} reverse relation for {} is {}",getUseCaseDescriptor().getId(),relation,toDeleteReverseRelation);
2022-05-10 10:58:40 +02:00
// check if relation existing
List<Relationship> relations = toUpdate.getRelationships();
if(relations!=null && !relations.isEmpty()){
int beforeSize = relations.size();
2022-10-25 13:03:14 +02:00
ArrayList<Relationship> toRemove = new ArrayList<>();
for(Relationship r : toUpdate.getRelationships()){
if(r.getRelationshipName().equals(relation)&&
r.getTargetUCD().equals(toUseTargetUCD)&&
r.getTargetID().equals(targetId)){
// set to be remove
log.debug("Removing {} ",r);
toRemove.add(r);
// delete reverse relation
if(toDeleteReverseRelation!=null){
log.debug("Removing reverse of {} ",r);
2022-11-11 12:04:55 +01:00
ProfiledMongoManager otherManager = (toUseTargetUCD.equals(this.useCaseDescriptor.getId()))?this:new ProfiledMongoManager(targetUCD);
2022-10-25 13:03:14 +02:00
Project other = getByID(targetId);
2022-10-25 16:57:41 +02:00
other = otherManager.lock(other.getId(),"Remove reverse relation "+toDeleteReverseRelation + " toward "+getUseCaseDescriptor().getId()+":"+id);
2022-10-25 13:03:14 +02:00
final String finalToDeleteReverseRelation = toDeleteReverseRelation;
other.getRelationships().removeIf(revRel ->revRel.getRelationshipName().equals(finalToDeleteReverseRelation)&&
revRel.getTargetID().equals(id)&&revRel.getTargetUCD().equals(getUseCaseDescriptor().getId()));
otherManager.unlockAndUpdate(other);
}
}
}
toUpdate.getRelationships().removeAll(toRemove);
2022-05-10 10:58:40 +02:00
// update only if something changed
2022-09-30 15:34:35 +02:00
if(toUpdate.getRelationships().size()!=beforeSize) {
log.debug("Removed {} relations from {} ",(toUpdate.getRelationships().size()!=beforeSize),id);
return unlockAndUpdate(toUpdate);
}
2022-05-10 10:58:40 +02:00
}
2022-09-30 15:34:35 +02:00
log.debug("Relationship not found. Unlocking.. ");
2022-09-30 14:57:28 +02:00
return unlock(toUpdate);
2022-05-10 10:58:40 +02:00
}catch(Throwable t){
log.error("Unexpected exception ",t);
unlock(toUpdate);
throw t;
}
}
2022-01-17 18:19:40 +01:00
2022-03-04 14:23:20 +01:00
private Project onUpdate(Project toUpdate) throws EventException {
2022-01-17 18:19:40 +01:00
UserUtils.AuthenticatedUser u = UserUtils.getCurrent();
toUpdate.getInfo().setLastEditInfo(u.asInfo());
toUpdate.setVersion(toUpdate.getVersion().withIncPatch());
2022-02-17 16:01:39 +01:00
return triggerEvent(toUpdate,EventExecutionRequest.Events.ON_INIT_DOCUMENT,null);
2021-12-01 11:13:34 +01:00
}
2022-02-17 16:01:39 +01:00
2022-04-08 13:17:52 +02:00
@Override
2022-03-29 18:06:09 +02:00
public void delete(String id,boolean force) throws DeletionException, InvalidUserRoleException, ProjectLockedException, ProjectNotFoundException, UnauthorizedAccess, JsonProcessingException, InvalidLockException {
log.info("Deleting by ID {}, force {}",id,force);
2022-03-24 17:44:00 +01:00
Project doc =lock(id,"Deletion { force : "+force+"}");
2022-05-31 16:24:23 +02:00
boolean deleted = false;
2022-03-29 18:06:09 +02:00
try {
2022-03-24 17:44:00 +01:00
User u = UserUtils.getCurrent().asInfo().getUser();
2022-03-29 18:06:09 +02:00
final DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
log.debug("Delete project {} [{}] , policy for {} is {} ", id, useCaseDescriptor.getId(), u, policy);
if (policy == null) throw new InvalidUserRoleException("No policy defined for current user roles " + u.getRoles());
if (!policy.canWrite(doc, u)) throw new UnauthorizedAccess("No edit rights on project " + id);
doc = triggerEvent(doc, EventExecutionRequest.Events.ON_DELETE_DOCUMENT, new Document("force", force));
//Only continue deleting if event was ok
if(doc.getLifecycleInformation().getLastOperationStatus().equals(LifecycleInformation.Status.OK)) {
try {
WorkspaceManager ws = new WorkspaceManager();
// Get All registered Filesets with payloads
JSONPathWrapper wrapper = new JSONPathWrapper(useCaseDescriptor.getSchema().toJson());
2022-05-17 11:43:50 +02:00
for (Object obj : wrapper.getByPath("$..[?(@." + RegisteredFileSet.PAYLOADS + ")]")) {
2022-03-29 18:06:09 +02:00
Document fs = Serialization.asDocument(obj);
log.debug("Deleting {}",obj);
String folderId = fs.getString(RegisteredFileSet.FOLDER_ID);
ws.deleteItem(folderId);
}
}finally {
2022-05-31 16:24:23 +02:00
super.deleteDoc(asId(id));
deleted = true;
2022-03-29 18:06:09 +02:00
}
2021-12-01 11:13:34 +01:00
}
2022-03-29 18:06:09 +02:00
} catch (ConfigurationException | StorageHubException e) {
log.error("Exception while trying to delete {} [UCID {}]",id,useCaseDescriptor.getId());
throw new DeletionException("Unable to contact Storage ",e);
} finally{
2022-05-31 16:24:23 +02:00
if(doc!=null && !deleted) unlockAndUpdate(doc);
2022-03-29 18:06:09 +02:00
}
2021-12-01 11:13:34 +01:00
}
@Override
2022-03-24 17:44:00 +01:00
public Project getByID(String id) throws ProjectNotFoundException, InvalidUserRoleException, UnauthorizedAccess {
User u = UserUtils.getCurrent().asInfo().getUser();
DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
log.info("Accessing Project {} [{}] , policy for {} is {} ",id,useCaseDescriptor.getId(),u,policy);
if(policy == null) {
log.warn("No policy found for {}. Returning empty ", u);
throw new InvalidUserRoleException("No policy defined for current user roles "+u.getRoles());
}
Document doc=getDocById(asId(id),
2022-04-01 19:11:11 +02:00
(policy==null||policy.getEnforcer()==null)?null:policy.getEnforcer().getFilterDocument());
2022-03-18 18:35:43 +01:00
if(doc==null) throw new ProjectNotFoundException("No document with ID "+id);
2022-03-24 17:44:00 +01:00
Project p = convert(doc, Project.class);
if(!policy.canRead(p,u)) throw new UnauthorizedAccess("No access rights on "+id);
return p;
2021-12-01 11:13:34 +01:00
}
@Override
2022-03-24 17:44:00 +01:00
public Iterable<Document> query(QueryRequest queryRequest) throws InvalidUserRoleException {
2022-03-04 18:28:45 +01:00
LinkedBlockingQueue queue=new LinkedBlockingQueue<Project>();
2022-03-24 17:44:00 +01:00
User u = UserUtils.getCurrent().asInfo().getUser();
final DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
log.info("Querying {} [{}] , policy for {} is {} ",queryRequest,useCaseDescriptor.getId(),u,policy);
// NB cannot check ownership on returned values, must specify filter
if(policy == null) {
log.warn("No policy found for {}. Returning empty ", u);
throw new InvalidUserRoleException("No policy defined for current user roles " + u.getRoles());
}
2022-04-01 19:11:11 +02:00
if(policy.getPolicy().getRead().equals(DataAccessPolicy.Policy.Type.none)) {
2022-03-24 17:44:00 +01:00
log.info("Read is NONE : Returning empty collection");
return queue;
}
// NB cannot check ownership on returned values, must specify filter
Document finalFilter=new Document();
if(queryRequest.getFilter()!=null)
finalFilter.putAll(queryRequest.getFilter());
2022-04-01 19:11:11 +02:00
if(policy.getEnforcer() != null)
finalFilter.putAll(policy.getEnforcer().getFilterDocument());
if(policy.getPolicy().getRead().equals(DataAccessPolicy.Policy.Type.own))
2022-03-24 17:44:00 +01:00
finalFilter.put(Project.INFO+"."+PublicationInfo.CREATION_INFO+"."+AccountingInfo.USER+"."+User.USERNAME,u.getUsername());
queryRequest.setFilter(finalFilter);
log.debug("Final filter is {}",queryRequest.getFilter());
2022-03-11 16:42:33 +01:00
queryDoc(queryRequest).forEach(
2021-12-07 11:16:26 +01:00
(Consumer<? super Document>) (Document d)->{try{
queue.put(d);
}catch(Throwable t){log.warn("Unable to translate "+d);}});
log.info("Returned {} elements ",queue.size());
return queue;
}
@Override
2022-03-24 17:44:00 +01:00
public Iterable<Project> filter(QueryRequest queryRequest) throws InvalidUserRoleException {
2022-03-04 18:28:45 +01:00
LinkedBlockingQueue queue=new LinkedBlockingQueue<Project>();
2022-03-24 17:44:00 +01:00
User u = UserUtils.getCurrent().asInfo().getUser();
final DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
log.info("Querying {} [{}] , policy for {} is {} ",queryRequest,useCaseDescriptor.getId(),u,policy);
// NB cannot check ownership on returned values, must specify filter
if(policy == null) {
log.warn("No policy found for {}. Returning empty ", u);
throw new InvalidUserRoleException("No policy defined for current user roles " + u.getRoles());
}
2022-04-01 19:11:11 +02:00
if(policy.getPolicy().getRead().equals(DataAccessPolicy.Policy.Type.none)) {
2022-03-24 17:44:00 +01:00
log.info("Read is NONE : Returning empty collection");
return queue;
}
// NB cannot check ownership on returned values, must specify filter
Document finalFilter=new Document();
if(queryRequest.getFilter()!=null)
finalFilter.putAll(queryRequest.getFilter());
2022-04-01 19:11:11 +02:00
if(policy.getEnforcer() != null)
finalFilter.putAll(policy.getEnforcer().getFilterDocument());
if(policy.getPolicy().getRead().equals(DataAccessPolicy.Policy.Type.own))
2022-03-24 17:44:00 +01:00
finalFilter.put(Project.INFO+"."+PublicationInfo.CREATION_INFO+"."+AccountingInfo.USER+"."+User.USERNAME,u.getUsername());
queryRequest.setFilter(finalFilter);
log.debug("Final filter is {}",queryRequest.getFilter());
2022-03-11 16:42:33 +01:00
queryDoc(queryRequest).forEach(
2021-12-01 11:13:34 +01:00
(Consumer<? super Document>) (Document d)->{try{
queue.put(d);
}catch(Throwable t){log.warn("Unable to translate "+d);}});
log.info("Returned {} elements ",queue.size());
return queue;
}
@Override
2022-04-08 13:17:52 +02:00
public Project performStep(String id, String step, Document options) throws StepException, JsonProcessingException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess, ConfigurationException, InsufficientPrivileges {
2022-03-18 18:35:43 +01:00
Project document = lock(id,"Step "+step+" execution");
2022-03-28 16:35:30 +02:00
try {
2022-03-24 17:44:00 +01:00
User u = UserUtils.getCurrent().asInfo().getUser();
2022-03-28 16:35:30 +02:00
final DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
log.info("Registering Fileset for {} [{}] , policy for {} is {} ", id, useCaseDescriptor.getId(), u, policy);
2022-03-24 17:44:00 +01:00
// NB cannot check ownership on returned values, must specify filter
2022-03-28 16:35:30 +02:00
if (policy == null) {
2022-03-24 17:44:00 +01:00
log.warn("No policy found for {}. Returning empty ", u);
throw new InvalidUserRoleException("No policy defined for current user roles " + u.getRoles());
}
2022-03-28 16:35:30 +02:00
if (!policy.canWrite(document, u)) throw new UnauthorizedAccess("No edit rights on project " + id);
2022-03-24 17:44:00 +01:00
2022-02-17 16:01:39 +01:00
document.getLifecycleInformation().cleanState();
document = step(document, step, options);
2022-04-08 15:20:21 +02:00
return unlockAndUpdate(document);
}catch (UnrecognizedStepException | ConfigurationException | InsufficientPrivileges e){
log.debug("Unable to perform step ",e);
unlock(document);
2022-03-28 16:35:30 +02:00
throw e;
2022-04-08 15:20:21 +02:00
} catch(Throwable t) {
log.error("[UseCaseDescriptor {} ] ERROR Invoking Step {} on document {}", useCaseDescriptor.getId(), step, id, t);
2022-02-14 17:06:32 +01:00
LifecycleInformation info = new LifecycleInformation();
info.setPhase(document.getLifecycleInformation().getPhase());
info.setLastOperationStatus(LifecycleInformation.Status.ERROR);
info.addErrorMessage(t.getMessage());
info.setLastInvokedStep(step);
document.setLifecycleInformation(info);
2022-04-08 15:20:21 +02:00
return unlockAndUpdate(document);
2022-02-14 17:06:32 +01:00
}
2021-12-01 11:13:34 +01:00
}
2022-01-17 18:19:40 +01:00
/**
* NB Put at path :
*
2022-01-27 15:02:53 +01:00
* Path Examples
* artifact
* images
* images[1]
2022-02-15 19:02:44 +01:00
* layers[?(@.name = 'myName')].fileset
2022-01-27 15:02:53 +01:00
*
2022-01-17 18:19:40 +01:00
*
*
*/
2021-12-01 11:13:34 +01:00
@Override
2022-04-08 15:20:21 +02:00
public Project registerFileSet(String id, RegisterFileSetRequest request) throws ConfigurationException, StorageHubException, StorageException, JsonProcessingException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess {
2022-03-04 14:23:20 +01:00
log.info("Registering Fileset for {} [useCaseDescriptor ID {}], Request is {} ",id, useCaseDescriptor.getId(),request);
2022-01-27 15:02:53 +01:00
2022-02-16 14:54:48 +01:00
List<TempFile> files=request.getStreams();
2022-01-27 15:02:53 +01:00
Document attributes =request.getAttributes();
2022-03-18 18:35:43 +01:00
Project doc=lock(id,"Register Fileset");
try {
2022-03-24 17:44:00 +01:00
// Checking user rights on proj
User u = UserUtils.getCurrent().asInfo().getUser();
final DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
log.info("Registering Fileset for {} [{}] , policy for {} is {} ",id,useCaseDescriptor.getId(),u,policy);
// NB cannot check ownership on returned values, must specify filter
if(policy == null) {
log.warn("No policy found for {}. Returning empty ", u);
throw new InvalidUserRoleException("No policy defined for current user roles " + u.getRoles());
}
if(!policy.canWrite(doc,u)) throw new UnauthorizedAccess("No edit rights on project "+id);
2022-03-18 18:35:43 +01:00
doc.getLifecycleInformation().cleanState();
doc.getLifecycleInformation().setLastOperationStatus(LifecycleInformation.Status.OK);
2022-02-17 16:01:39 +01:00
2022-03-18 18:35:43 +01:00
WorkspaceManager ws = new WorkspaceManager();
2022-04-27 19:36:10 +02:00
StorageUtils storage = ImplementationProvider.get().getProvidedObjectByClass(StorageUtils.class);
2022-01-17 18:19:40 +01:00
2022-03-18 18:35:43 +01:00
log.debug("Checking field {} definition in {}", request.getFieldDefinitionPath(), useCaseDescriptor.getId());
Field fieldDefinition = getFieldDefinition(useCaseDescriptor, request.getFieldDefinitionPath());
2022-02-15 19:02:44 +01:00
2022-03-18 18:35:43 +01:00
JSONPathWrapper docWrapper = new JSONPathWrapper(doc.getTheDocument().toJson());
2022-02-01 15:24:39 +01:00
2022-03-18 18:35:43 +01:00
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.isEmpty())
throw new WebApplicationException("PArent path not found at " + request.getParentPath(), Response.Status.BAD_REQUEST);
2022-02-15 19:02:44 +01:00
2022-03-18 18:35:43 +01:00
String parentMatchingPath = matchingPaths.get(0);
List<Object> foundElementsByMatchingPaths = docWrapper.getByPath(parentMatchingPath);
if (foundElementsByMatchingPaths == null || foundElementsByMatchingPaths.isEmpty())
throw new WebApplicationException("No element found at " + parentMatchingPath, Response.Status.BAD_REQUEST);
2022-03-04 11:30:48 +01:00
2022-03-18 18:35:43 +01:00
Document parent = Serialization.asDocument(foundElementsByMatchingPaths.get(0));
2022-01-17 18:19:40 +01:00
2022-05-18 18:24:57 +02:00
Access toSetAccess = doc.getInfo().getAccess();
if(request.getToSetAccess()!=null){
//TODO validate specified Access
toSetAccess = request.getToSetAccess();
}
2022-03-18 18:35:43 +01:00
// PREPARE REGISTERED FS
2022-01-17 18:19:40 +01:00
2022-02-16 14:54:48 +01:00
// MANAGE CLASH
2022-03-18 18:35:43 +01:00
switch (request.getClashOption()) {
2022-01-27 15:02:53 +01:00
case REPLACE_EXISTING: {
2022-03-18 18:35:43 +01:00
if (fieldDefinition.isCollection())
throw new WebApplicationException("Cannot replace repeatable field " + request.getFieldDefinitionPath() + ".", Response.Status.BAD_REQUEST);
2022-02-16 14:54:48 +01:00
// DELETE EXISTING AND PUT
2022-03-18 18:35:43 +01:00
RegisteredFileSet toDelete = Serialization.convert(parent.get(request.getFieldName()), RegisteredFileSet.class);
2022-03-29 18:06:09 +02:00
if (!(toDelete == null) && !(toDelete.isEmpty())) {
String path = parentMatchingPath+"."+request.getFieldName();
deleteFileSetRoutine(doc, false, path);
2022-03-18 18:35:43 +01:00
2022-03-29 18:06:09 +02:00
}
2022-05-18 18:24:57 +02:00
RegisteredFileSet fs = prepareRegisteredFileSet(toSetAccess, doc.getId(), useCaseDescriptor.getId(), request.getAttributes(), files, storage, ws);
2022-03-18 18:35:43 +01:00
log.debug("Registered Fileset for [ID {} useCaseDescriptor {}] is {} ", fs, doc.getId(), doc.getProfileID());
docWrapper.putElement(parentMatchingPath, request.getFieldName(), fs);
break;
}
2022-02-16 14:54:48 +01:00
case MERGE_EXISTING: {
2022-03-18 18:35:43 +01:00
if (fieldDefinition.isCollection())
throw new WebApplicationException("Cannot merge repeatable field " + request.getFieldDefinitionPath() + ".", Response.Status.BAD_REQUEST);
RegisteredFileSet original = Serialization.convert(parent.get(request.getFieldName()), RegisteredFileSet.class);
2022-02-16 14:54:48 +01:00
// MERGE ATTRIBUTES AND PUT
2022-03-18 18:35:43 +01:00
Document toUseAttributes = request.getAttributes();
if (original != null) toUseAttributes.putAll(original);
2022-05-18 18:24:57 +02:00
RegisteredFileSet fs = prepareRegisteredFileSet(toSetAccess, doc.getId(), useCaseDescriptor.getId(), toUseAttributes, files, storage, ws);
2022-03-18 18:35:43 +01:00
log.debug("Registered Fileset for [ID {} useCaseDescriptor {}] is {} ", fs, doc.getId(), doc.getProfileID());
docWrapper.putElement(parentMatchingPath, request.getFieldName(), fs);
break;
}
2022-02-16 14:54:48 +01:00
case APPEND: {
2022-03-18 18:35:43 +01:00
if (!fieldDefinition.isCollection())
throw new WebApplicationException("Cannot add to single field " + request.getFieldDefinitionPath() + ".", Response.Status.BAD_REQUEST);
2022-05-18 18:24:57 +02:00
RegisteredFileSet fs = prepareRegisteredFileSet(toSetAccess, doc.getId(), useCaseDescriptor.getId(), request.getAttributes(), files, storage, ws);
2022-03-18 18:35:43 +01:00
log.debug("Registered Fileset for [ID {} useCaseDescriptor {}] is {} ", fs, doc.getId(), doc.getProfileID());
2022-01-27 15:02:53 +01:00
2022-03-18 18:35:43 +01:00
docWrapper.addElementToArray(String.format("%1ds['%2$s']", parentMatchingPath, request.getFieldName()), fs);
break;
}
default: {
throw new WebApplicationException("Unexpected clash policy " + request.getClashOption(), Response.Status.BAD_REQUEST);
}
}
2022-01-27 15:02:53 +01:00
2022-01-17 18:19:40 +01:00
2022-03-18 18:35:43 +01:00
log.debug("Setting result on profiled document");
doc.setTheDocument(Document.parse(docWrapper.getValueCTX().jsonString()));
2022-01-17 18:19:40 +01:00
2022-03-18 18:35:43 +01:00
doc = onUpdate(doc);
return unlockAndUpdate(doc);
2022-04-08 15:20:21 +02:00
}catch (Throwable t) {
log.warn("Unexpected Exception while trying to registering fileset on {}.", id, t);
log.debug("Request was {}", request);
log.debug("Complete doc was {} ", doc);
unlock(doc);
throw t;
2022-03-18 18:35:43 +01:00
}
2021-12-01 11:13:34 +01:00
}
2021-12-15 19:10:19 +01:00
2022-03-18 18:35:43 +01:00
2022-01-18 12:01:33 +01:00
@Override
2022-03-24 17:44:00 +01:00
public Project deleteFileSet(String id, String path, Boolean force) throws ConfigurationException, StorageHubException, JsonProcessingException, DeletionException, EventException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess {
2022-03-04 14:23:20 +01:00
log.info("Deleting Fileset for {} [useCaseDescriptor ID {}], at {} [force {} ]",id, useCaseDescriptor.getId(),path,force);
2022-03-18 18:35:43 +01:00
Project doc = lock(id,"Fileset Deletion");
try {
2022-03-24 17:44:00 +01:00
User u = UserUtils.getCurrent().asInfo().getUser();
final DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
2022-03-29 18:06:09 +02:00
log.debug("Deleting Fileset for {} [{}] , policy for {} is {} ",doc.getId(),useCaseDescriptor.getId(),u,policy);
2022-03-24 17:44:00 +01:00
// NB cannot check ownership on returned values, must specify filter
if(policy == null) {
log.warn("No policy found for {}. Returning empty ", u);
throw new InvalidUserRoleException("No policy defined for current user roles " + u.getRoles());
}
2022-03-29 18:06:09 +02:00
if(!policy.canWrite(doc,u)) throw new UnauthorizedAccess("No edit rights on project "+doc.getId());
2022-03-24 17:44:00 +01:00
2022-03-18 18:35:43 +01:00
doc.getLifecycleInformation().cleanState();
doc.getLifecycleInformation().cleanState().setLastOperationStatus(LifecycleInformation.Status.OK);
2022-03-29 18:06:09 +02:00
doc= deleteFileSetRoutine(doc,force,path);
2022-03-18 18:35:43 +01:00
return unlockAndUpdate(doc);
2022-04-08 15:20:21 +02:00
}catch (Throwable t) {
log.warn("Unexpected Exception while trying to delete fileset on {}.", id, t);
unlock(doc);
throw t;
2022-03-18 18:35:43 +01:00
}
2022-01-18 12:01:33 +01:00
}
2022-01-17 18:19:40 +01:00
@Override
public Project forceUnlock(String id) throws InvalidUserRoleException, ProjectNotFoundException, UnauthorizedAccess, JsonProcessingException, InvalidLockException {
Project toUnlock = null;
try{
toUnlock = lock(id,"Check locked for force unlock");
throw new WebApplicationException("Project "+id+" not locked", Response.Status.EXPECTATION_FAILED);
}catch (ProjectLockedException e){
// expected exception
toUnlock = getByID(id);
}finally {
2022-05-17 15:43:19 +02:00
if(toUnlock!=null)
return unlock(toUnlock);
else throw new WebApplicationException("Unable to get Project "+id, Response.Status.EXPECTATION_FAILED);
}
}
@Override
public Project setAccessPolicy(String id, Access access) throws InvalidUserRoleException, ProjectLockedException, ProjectNotFoundException, UnauthorizedAccess, JsonProcessingException, InvalidLockException, EventException {
log.trace("UCD {}, Project {} : Setting Access {}",useCaseDescriptor.getId(),id,access);
Project toUpdate=lock(id,"Set Access policy");
try {
User u = UserUtils.getCurrent().asInfo().getUser();
final DataAccessPolicy policy = useCaseDescriptor.getMatching(u);
if(policy == null) {
log.warn("No policy found for {}. Returning empty ", u);
throw new InvalidUserRoleException("No policy defined for current user roles " + u.getRoles());
}
if(!policy.canWrite(toUpdate,u)) throw new UnauthorizedAccess("No edit rights on project "+id);
toUpdate.getInfo().setAccess(access);
toUpdate.getLifecycleInformation().cleanState();
toUpdate = onUpdate(toUpdate);
return unlockAndUpdate(toUpdate);
}catch(Throwable t){
log.error("Unexpected exception ",t);
unlock(toUpdate);
throw t;
}
}
2022-03-29 18:06:09 +02:00
private Project deleteFileSetRoutine(Project doc,Boolean force, String path) throws ConfigurationException, StorageHubException {
2022-08-04 16:48:49 +02:00
log.info("Delete[force : {}] FS at {} for {}:{}",force,path,doc.getProfileID(),doc.getId());
2022-03-29 18:06:09 +02:00
JSONPathWrapper wrapper = new JSONPathWrapper(doc.getTheDocument().toJson());
List<String> matchingPaths = wrapper.getMatchingPaths(path);
if (matchingPaths.isEmpty())
throw new WebApplicationException("No Registered FileSet found at " + path, Response.Status.BAD_REQUEST);
if (matchingPaths.size() > 1)
throw new WebApplicationException("Multiple Fileset (" + matchingPaths.size() + ") matching " + path, Response.Status.BAD_REQUEST);
2022-08-04 16:48:49 +02:00
2022-08-04 17:02:47 +02:00
RegisteredFileSet fs = Serialization.convert(wrapper.getByPath(path).get(0), RegisteredFileSet.class);
2022-03-29 18:06:09 +02:00
log.debug("Going to delete {}", fs);
doc = triggerEvent(doc,EventExecutionRequest.Events.ON_DELETE_FILESET,new Document("force",force).append("path",path));
// Actually delete only if event was ok
if(doc.getLifecycleInformation().getLastOperationStatus().equals(LifecycleInformation.Status.OK)) {
// Delete from storage
if(fs.getFolderId()!=null) {
log.info("Deleting Fileset Folder ID {} ",fs.getFolderId());
new WorkspaceManager().deleteItem(fs.getFolderId());
}
log.debug("Removing FS from document [ID : ] by path {}", doc.getId(), path);
// Delete from document
wrapper.setElement(path, null);
}
return doc;
}
2022-02-04 17:45:47 +01:00
@Override
2022-03-18 15:38:24 +01:00
public Configuration getConfiguration() throws ConfigurationException{
2023-01-10 15:57:40 +01:00
String context = UserUtils.getCurrent().getContext();
log.debug("Asking configuration for {} in {} ", useCaseDescriptor.getId(), context);
2022-03-10 18:15:10 +01:00
Configuration toReturn= new Configuration();
List<Archive> archives = new ArrayList<>();
2022-03-18 15:38:24 +01:00
toReturn.setArchives(archives);
2022-03-11 18:11:32 +01:00
List<Index> indexes=new ArrayList<>();
2022-03-18 15:38:24 +01:00
toReturn.setIndexes(indexes);
2022-03-10 18:15:10 +01:00
// Set Basic Info
toReturn.setProfileId(this.getUseCaseDescriptor().getId());
2023-01-10 15:57:40 +01:00
toReturn.setContext(context);
2022-03-10 18:15:10 +01:00
toReturn.setLastUpdatedTime(LocalDateTime.now());
// Add Mongo Info
Archive mongoArchive = new Archive("DOCUMENT-STORE-COLLECTION");
2022-03-11 16:42:33 +01:00
MongoCollection coll=getCollection();
2022-03-10 18:15:10 +01:00
mongoArchive.put("count",coll.count());
2022-03-11 16:42:33 +01:00
mongoArchive.put("collection_name",getToUseCollectionName());
2022-05-18 18:24:57 +02:00
// Get counts by PHASE, Status
try {
ArrayList<Document> counts = new ArrayList<>();
coll.aggregate(Collections.singletonList(Document.parse(
"{\"$group\" : " +
"{\"_id\":{\"phase\":\"$_lifecycleInformation._phase\",\"status\":\"$_lifecycleInformation._lastOperationStatus\"}, " +
"\"count\":{\"$sum\":1}}}"))).forEach((Consumer) doc -> {
try { counts.add(Serialization.asDocument(doc)); } catch (JsonProcessingException e) { log.warn("Unable to write aggregated results ",e); } });
mongoArchive.put("countByPhase",counts);
}catch (Throwable t){
toReturn.addErrorMessage("Unable to get PHASE statistics "+t.getMessage());
log.error("Unable to get PHASE statistics",t);
}
2022-03-10 18:15:10 +01:00
archives.add(mongoArchive);
2022-03-11 18:11:32 +01:00
// TODO ADD TEXT INDEXES
2022-03-10 18:15:10 +01:00
// Set WS Info
try {
archives.add(new WorkspaceManager().getConfiguration());
2022-03-18 15:38:24 +01:00
}catch (Exception e) {
toReturn.addErrorMessage("Unable to get WS info "+e.getMessage());
log.error("Unable to get WS Configuration",e);
2022-03-10 18:15:10 +01:00
}
2022-03-11 18:11:32 +01:00
// ADD LC Infos
AccountingInfo user = UserUtils.getCurrent().asInfo();
2022-03-18 15:38:24 +01:00
try{
Configuration lcConfig = getLCManager().getCurrentConfiguration(new BaseRequest(useCaseDescriptor,user.getUser(),user.getContext()));
2022-04-08 13:17:52 +02:00
log.info("Configuration is {} ",lcConfig);
if(lcConfig.getArchives()!=null)
archives.addAll(lcConfig.getArchives());
2022-03-11 18:11:32 +01:00
2022-04-08 13:17:52 +02:00
if(lcConfig.getIndexes()!=null)
indexes.addAll(lcConfig.getIndexes());
2022-04-07 18:12:42 +02:00
}catch(Throwable e){
2022-03-18 15:38:24 +01:00
toReturn.addErrorMessage("Unable to get Lifecycle info "+e.getMessage());
log.error("Unable to get Lifecycle info ",e);
}
2022-03-11 18:11:32 +01:00
2022-02-04 17:45:47 +01:00
log.debug("Returning current configuration {}",toReturn);
return toReturn;
}
2022-01-17 18:19:40 +01:00
2022-03-29 18:06:09 +02:00
2022-04-08 13:17:52 +02:00
private Project step(Project theDocument, String step, Document callParameters) throws InsufficientPrivileges, ConfigurationException, StepException {
2022-03-28 16:35:30 +02:00
try {
log.info("[UseCaseDescriptor {}] Invoking Step {} on {}", useCaseDescriptor.getId(), step, getManager().getDescriptor());
AccountingInfo user = UserUtils.getCurrent().asInfo();
2022-03-24 17:44:00 +01:00
2022-03-28 16:35:30 +02:00
StepExecutionRequest request = new StepExecutionRequest(useCaseDescriptor, user.getUser(), user.getContext(), theDocument, step);
2022-04-08 13:17:52 +02:00
request.setCallParameters(callParameters);
2022-02-14 17:06:32 +01:00
2022-03-28 16:35:30 +02:00
log.debug("Requesting Step Execution {}", request);
StepExecutionReport report = getManager().performStep(request);
Project toReturn = report.prepareResult();
2022-02-17 16:01:39 +01:00
2022-03-28 16:35:30 +02:00
// EVENTS
if (report.getToTriggerEvents() != null) {
2022-02-17 16:01:39 +01:00
Iterator<EventExecutionRequest> eventIT = report.getToTriggerEvents().listIterator();
while (!toReturn.getLifecycleInformation().getLastOperationStatus().equals(LifecycleInformation.Status.ERROR)
&& eventIT.hasNext()) {
EventExecutionRequest triggerRequest = eventIT.next();
log.info("Triggering {} ", triggerRequest);
toReturn = triggerEvent(toReturn, triggerRequest.getEvent(), triggerRequest.getCallParameters());
}
}
2022-02-14 17:06:32 +01:00
2022-03-28 16:35:30 +02:00
// STEPS
if (report.getCascadeSteps() != null) {
2022-02-17 16:01:39 +01:00
Iterator<StepExecutionRequest> stepIT = report.getCascadeSteps().listIterator();
while (!toReturn.getLifecycleInformation().getLastOperationStatus().equals(LifecycleInformation.Status.ERROR)
&& stepIT.hasNext()) {
StepExecutionRequest triggerRequest = stepIT.next();
log.info("Triggering {} ", triggerRequest);
toReturn = step(toReturn, triggerRequest.getStep(), triggerRequest.getCallParameters());
}
}
2022-03-28 16:35:30 +02:00
return report.prepareResult();
2022-04-08 13:17:52 +02:00
}catch (InsufficientPrivileges | ConfigurationException | UnrecognizedStepException e){
2022-03-28 16:35:30 +02:00
throw e;
2022-02-17 16:01:39 +01:00
}catch(Throwable t){
log.error("Unable to perform step "+step,t);
theDocument.getLifecycleInformation().addErrorMessage("Unable to perform step "+step+" cause : "+ t.getMessage());
theDocument.getLifecycleInformation().setLastOperationStatus(LifecycleInformation.Status.ERROR);
return theDocument;
}
2021-12-15 19:10:19 +01:00
}
2022-01-17 18:19:40 +01:00
2022-03-18 18:35:43 +01:00
private Project triggerEvent(Project project, String event, Document parameters) {
2022-02-17 16:01:39 +01:00
try{
2022-04-08 13:17:52 +02:00
log.info("[UseCaseDescriptor {}] triggering event {} on {}" , useCaseDescriptor.getId(),event,getManager().getDescriptor());
2022-03-11 18:11:32 +01:00
AccountingInfo user= UserUtils.getCurrent().asInfo();
2022-04-08 13:17:52 +02:00
EventExecutionRequest request= new EventExecutionRequest(useCaseDescriptor,user.getUser(),user.getContext(),project,event);
2022-05-31 16:10:41 +02:00
request.setCallParameters(parameters);
2022-04-08 13:17:52 +02:00
log.debug("Triggering {}",request);
DocumentHandlingReport report = getManager().onEvent(request);
return report.prepareResult();
2022-02-17 16:01:39 +01:00
} catch (Throwable t){
log.error("Unable to trigger event "+event,t);
2022-03-18 18:35:43 +01:00
project.getLifecycleInformation().addErrorMessage("Unable to trigger "+event+" cause : "+ t.getMessage());
project.getLifecycleInformation().setLastOperationStatus(LifecycleInformation.Status.ERROR);
return project;
2022-02-17 16:01:39 +01:00
}
2022-02-14 17:06:32 +01:00
}
2022-01-17 18:19:40 +01:00
2022-05-18 18:24:57 +02:00
private static final RegisteredFileSet prepareRegisteredFileSet(Access toSetAccess,String docID, String profileID,
2022-01-17 18:19:40 +01:00
Document attributes,List<TempFile> files, StorageUtils storage,WorkspaceManager ws) throws StorageHubException, StorageException {
2023-01-10 11:42:09 +01:00
log.debug("Preparing Registered FileSet {}");
2022-02-01 15:24:39 +01:00
RegisteredFileSet toReturn = new RegisteredFileSet();
if(attributes!=null) toReturn.putAll(attributes);
2022-02-16 14:54:48 +01:00
String uuid = UUID.randomUUID().toString();
toReturn.putIfAbsent(RegisteredFileSet.UUID, uuid);
toReturn.putIfAbsent(RegisteredFileSet.CREATION_INFO,UserUtils.getCurrent().asInfo());
2022-05-18 18:24:57 +02:00
toReturn.putIfAbsent(RegisteredFileSet.ACCESS,toSetAccess);
2022-02-16 14:54:48 +01:00
// FOLDER
String folderID=toReturn.getFolderId();
log.trace("Folder ID is {} ",folderID);
FolderContainer sectionFolder=null;
if(folderID==null || folderID.isEmpty()) {
2022-11-04 17:48:04 +01:00
// Get BASE Folder for project
FolderContainer base = ws.getSubFolder(ws.getAppBase(),docID,"Base Folder for profiled document. UseCaseDescriptor " + profileID);
// Create Folder for FileSet
sectionFolder = ws.createFolder(new WorkspaceManager.FolderOptions(docID + "_" + uuid, "Registered Fileset uuid " + uuid, base));
2022-02-16 14:54:48 +01:00
toReturn.put(RegisteredFileSet.FOLDER_ID, sectionFolder.getId());
}else {
sectionFolder = ws.getFolderById(folderID);
}
2022-01-17 18:19:40 +01:00
ArrayList<RegisteredFile> registeredFiles=new ArrayList<>();
2022-02-16 14:54:48 +01:00
if(toReturn.containsKey(RegisteredFileSet.PAYLOADS))
registeredFiles.addAll(toReturn.getPayloads());
2022-01-17 18:19:40 +01:00
for (TempFile f : files) {
InputStream is=null;
try{
log.debug("Opening temp file {}",f);
2022-04-08 14:52:11 +02:00
String fileUrl=null;
if(f.getId()==null||f.getId().isEmpty())
fileUrl=f.getUrl();
else fileUrl=storage.getURL(f.getId());
2022-01-17 18:19:40 +01:00
log.debug("Got URL {} from ID {}",fileUrl,f.getId());
is=new URL(fileUrl).openStream();
RegisteredFile registered=ws.registerFile(new WorkspaceManager.FileOptions(f.getFilename(),is,
"Imported via gcube CMS service ", sectionFolder));
log.debug("Registered "+registered);
registeredFiles.add(registered);
}catch(StorageHubException | IOException e){
throw new StorageException("Unable to store "+f,e);
}finally{
if(is!=null)
IOUtils.closeQuietly(is);
}
}
2022-02-01 15:24:39 +01:00
toReturn.put(RegisteredFileSet.PAYLOADS,registeredFiles);
2022-02-16 14:54:48 +01:00
// TODO MERGE
//toReturn.remove(RegisteredFileSet.MATERIALIZATIONS);
2022-02-01 15:24:39 +01:00
return toReturn;
2022-01-17 18:19:40 +01:00
}
2022-01-31 13:09:54 +01:00
2022-02-16 14:54:48 +01:00
2022-03-04 14:23:20 +01:00
private static Field getFieldDefinition(UseCaseDescriptor useCaseDescriptor, String fieldPath)throws WebApplicationException{
JSONPathWrapper schemaWrapper= new JSONPathWrapper(useCaseDescriptor.getSchema().toJson());
2022-02-16 14:54:48 +01:00
List<Field> fieldDefinitions=schemaWrapper.getByPath(fieldPath,Field.class);
if(fieldDefinitions==null || fieldDefinitions.isEmpty())
2022-03-04 14:23:20 +01:00
throw new WebApplicationException("No Field found in schema "+ useCaseDescriptor.getId()+" at "+fieldPath, Response.Status.BAD_REQUEST);
2022-02-16 14:54:48 +01:00
if(fieldDefinitions.size()>1)
2022-03-04 14:23:20 +01:00
throw new WebApplicationException("Multiple field definitions ("+fieldDefinitions.size()+") found in "+ useCaseDescriptor.getId()+" for "+fieldPath,Response.Status.BAD_REQUEST);
2022-02-16 14:54:48 +01:00
Field fieldDefinition=Serialization.convert(fieldDefinitions.get(0),Field.class);
if(fieldDefinition==null)
2022-03-04 14:23:20 +01:00
throw new WebApplicationException("Found field is null ["+ useCaseDescriptor.getId()+" for "+fieldPath+"]",Response.Status.BAD_REQUEST);
2022-02-16 14:54:48 +01:00
log.trace("Field definition is {}",fieldDefinition);
return fieldDefinition;
2022-01-31 13:09:54 +01:00
}
2021-09-20 16:47:35 +02:00
}