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 ;
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-05-10 10:58:40 +02:00
import org.gcube.application.geoportal.common.model.document.relationships.Relationship ;
2022-04-01 19:11:11 +02:00
import org.gcube.application.geoportal.common.model.plugins.LifecycleManagerDescriptor ;
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-01-17 18:19:40 +01:00
import org.gcube.application.geoportal.common.faults.StorageException ;
2022-03-10 18:15:10 +01:00
import org.gcube.application.geoportal.common.model.configuration.Archive ;
2022-03-11 18:11:32 +01:00
import org.gcube.application.geoportal.common.model.configuration.Index ;
2021-12-07 16:42:39 +01:00
import org.gcube.application.geoportal.common.model.document.* ;
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-03-24 17:44:00 +01:00
import org.gcube.application.geoportal.common.model.useCaseDescriptor.DataAccessPolicy ;
2022-03-04 14:23:20 +01:00
import org.gcube.application.geoportal.common.model.useCaseDescriptor.Field ;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.HandlerDeclaration ;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor ;
2022-03-10 18:15:10 +01:00
import org.gcube.application.geoportal.common.model.configuration.Configuration ;
2021-12-01 11:13:34 +01:00
import org.gcube.application.geoportal.common.model.rest.QueryRequest ;
2022-01-27 15:02:53 +01:00
import org.gcube.application.geoportal.common.model.rest.RegisterFileSetRequest ;
import org.gcube.application.geoportal.common.model.rest.TempFile ;
2022-02-01 15:24:39 +01:00
import org.gcube.application.geoportal.common.model.JSONPathWrapper ;
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 15:34:22 +01:00
import org.gcube.application.cms.implementations.ImplementationProvider ;
2022-01-17 18:19:40 +01:00
import org.gcube.application.geoportal.service.engine.WorkspaceManager ;
2022-02-04 17:45:47 +01:00
import org.gcube.application.geoportal.common.model.rest.ConfigurationException ;
2022-02-18 18:11:34 +01:00
import org.gcube.application.geoportal.service.engine.providers.PluginManager ;
2022-03-23 18:38:07 +01:00
import org.gcube.application.geoportal.service.engine.providers.ucd.ProfileMap ;
2022-03-18 18:35:43 +01:00
import org.gcube.application.geoportal.service.model.internal.faults.* ;
2022-02-01 15:24:39 +01:00
import org.gcube.application.cms.serialization.Serialization ;
2021-12-07 16:12:43 +01:00
import org.gcube.application.geoportal.service.utils.UserUtils ;
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-02-01 15:24:39 +01:00
import static org.gcube.application.cms.serialization.Serialization.* ;
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
2022-03-04 18:28:45 +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 {
Project toUpdate = lock ( id , " Set Relation " ) ;
try {
// 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 ) ;
// add relation
Relationship rel = new Relationship ( ) ;
rel . setRelationshipName ( relation ) ;
rel . setTargetID ( targetId ) ;
rel . setTargetUCD ( targetUCD ) ;
return onUpdate ( toUpdate . addRelation ( rel ) ) ;
} 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 {
Project toUpdate = lock ( id , " Set Relation " ) ;
try {
// check if relation existing
List < Relationship > relations = toUpdate . getRelationships ( ) ;
if ( relations ! = null & & ! relations . isEmpty ( ) ) {
int beforeSize = relations . size ( ) ;
toUpdate . getRelationships ( ) . removeIf ( r - >
r . getRelationshipName ( ) . equals ( relation ) & &
r . getTargetUCD ( ) . equals ( targetUCD ) & &
r . getTargetID ( ) . equals ( targetId ) ) ;
// update only if something changed
if ( toUpdate . getRelationships ( ) . size ( ) ! = beforeSize ) return onUpdate ( toUpdate ) ;
}
return toUpdate ;
} 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-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 {
if ( force ) super . deleteDoc ( asId ( id ) ) ;
}
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 {
if ( doc ! = null ) unlockAndUpdate ( doc ) ;
}
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
2022-05-17 14:35:06 +02: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 ) ;
2022-05-17 14:35:06 +02:00
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 {
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 ) ;
RegisteredFileSet fs = Serialization . convert ( wrapper . getByPath ( path ) , RegisteredFileSet . class ) ;
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 {
2022-03-04 14:23:20 +01:00
log . debug ( " Asking configuration for {} in {} " , useCaseDescriptor . getId ( ) , UserUtils . getCurrent ( ) . getContext ( ) ) ;
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 ( ) ) ;
toReturn . setContext ( ContextUtils . getCurrentScope ( ) ) ;
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 ) ;
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 {
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 ( ) ) {
FolderContainer base = ws . createFolder ( new WorkspaceManager . FolderOptions (
2022-03-04 14:23:20 +01:00
docID , " Base Folder for profiled document. UseCaseDescriptor " + profileID , null ) ) ;
2022-02-16 14:54:48 +01:00
sectionFolder = ws . createFolder ( new WorkspaceManager . FolderOptions (
docID + " _ " + uuid , " Registered Fileset uuid " + uuid , base ) ) ;
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
}