@ -2,8 +2,10 @@ package org.gcube.application.geoportal.service.engine.mongo;
import com.fasterxml.jackson.core.JsonProcessingException ;
import com.mongodb.client.MongoDatabase ;
import com.vdurmont.semver4j.Semver ;
import lombok.Getter ;
import lombok.extern.slf4j.Slf4j ;
import org.apache.commons.io.IOUtils ;
import org.bson.Document ;
import org.bson.types.ObjectId ;
import org.gcube.application.cms.plugins.LifecycleManager ;
@ -11,21 +13,33 @@ import org.gcube.application.cms.plugins.faults.StepException;
import org.gcube.application.cms.plugins.model.PluginDescriptor ;
import org.gcube.application.cms.plugins.reports.ExecutionReport ;
import org.gcube.application.cms.plugins.requests.StepExecutionRequest ;
import org.gcube.application.geoportal.common.faults.StorageException ;
import org.gcube.application.geoportal.common.model.document.* ;
import org.gcube.application.geoportal.common.model.legacy.Concessione ;
import org.gcube.application.geoportal.common.model.legacy.WorkspaceContent ;
import org.gcube.application.geoportal.common.model.profile.Field ;
import org.gcube.application.geoportal.common.model.profile.HandlerDeclaration ;
import org.gcube.application.geoportal.common.model.profile.Profile ;
import org.gcube.application.geoportal.common.model.rest.QueryRequest ;
import org.gcube.application.geoportal.common.rest.TempFile ;
import org.gcube.application.geoportal.common.utils.JSONPathWrapper ;
import org.gcube.application.geoportal.common.utils.StorageUtils ;
import org.gcube.application.geoportal.service.engine.ImplementationProvider ;
import org.gcube.application.geoportal.service.engine.WorkspaceManager ;
import org.gcube.application.geoportal.service.model.internal.faults.ConfigurationException ;
import org.gcube.application.geoportal.service.model.internal.faults.DeletionException ;
import org.gcube.application.cms.Serialization ;
import org.gcube.application.geoportal.service.utils.UserUtils ;
import org.gcube.common.storagehub.client.dsl.FolderContainer ;
import org.gcube.common.storagehub.model.exceptions.StorageHubException ;
import javax.ws.rs.WebApplicationException ;
import javax.ws.rs.core.Response ;
import java.io.IOException ;
import java.io.InputStream ;
import java.net.URL ;
import java.security.InvalidParameterException ;
import java.util.ArrayList ;
import java.util.List ;
import java.util.Map ;
import java.util.concurrent.LinkedBlockingQueue ;
@ -89,22 +103,6 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
}
}
private ProfiledDocument onUpdate ( ProfiledDocument updatedDocument ) throws StepException {
UserUtils . AuthenticatedUser u = UserUtils . getCurrent ( ) ;
updatedDocument . getInfo ( ) . setLastEditInfo ( u . asInfo ( ) ) ;
return step ( updatedDocument , StepExecutionRequest . Steps . ON_UPDATE_DOCUMENT ) . getResult ( ) ;
}
// private Document asDocument(ProfiledDocument d) throws JsonProcessingException {
// return Document.parse(Serialization.write(d));
// }
//
// private ProfiledDocument asProfiledDocument(Document d) throws IOException {
// return Serialization.read(d.toJson(),ProfiledDocument.class);
// }
private String getCollectionName ( ) {
// TODO Profile can directly specify, use ID only as default
@ -138,11 +136,11 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
toRegister . setProfileID ( profile . getId ( ) ) ;
toRegister . setProfileVersion ( profile . getVersion ( ) ) ;
toRegister . setVersion ( new ComparableVersion ( "1.0.0" ) ) ;
toRegister . setVersion ( new Semver ( "1.0.0" ) ) ;
// Apply Lifecycle
toRegister = step ( toRegister , StepExecutionRequest . Steps . ON_INIT_DOCUMENT ). getResult ( ) ;
toRegister = step ( toRegister , StepExecutionRequest . Steps . ON_INIT_DOCUMENT ,null ). getResult ( ) ;
log . debug ( "Going to register {} " , toRegister ) ;
@ -154,10 +152,22 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
}
@Override
public ProfiledDocument update ( String id , Profiled Document toSet ) throws IOException , StepException {
public ProfiledDocument update ( String id , Document toSet ) throws IOException , StepException {
log . trace ( "Replacing {} " , toSet ) ;
toSet = onUpdate ( toSet ) ;
return convert ( replace ( asDocument ( toSet ) , getCollectionName ( ) ) , ProfiledDocument . class ) ;
ProfiledDocument toUpdate = getByID ( id ) ;
toUpdate . setTheDocument ( toSet ) ;
toUpdate = onUpdate ( toUpdate ) ;
return convert ( replace ( asDocument ( toUpdate ) , getCollectionName ( ) ) , ProfiledDocument . class ) ;
}
private ProfiledDocument onUpdate ( ProfiledDocument toUpdate ) throws StepException {
UserUtils . AuthenticatedUser u = UserUtils . getCurrent ( ) ;
toUpdate . getInfo ( ) . setLastEditInfo ( u . asInfo ( ) ) ;
toUpdate . setVersion ( toUpdate . getVersion ( ) . withIncPatch ( ) ) ;
return step ( toUpdate , StepExecutionRequest . Steps . ON_UPDATE_DOCUMENT , null ) . getResult ( ) ;
}
@Override
@ -190,8 +200,10 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
}
@Override
public ProfiledDocument getByID ( String id ) throws IOException {
return convert ( super . getById ( asId ( id ) , getCollectionName ( ) ) , ProfiledDocument . class ) ;
public ProfiledDocument getByID ( String id ) {
Document doc = super . getById ( asId ( id ) , getCollectionName ( ) ) ;
if ( doc = = null ) throw new WebApplicationException ( "No document with ID " + id ) ;
return convert ( doc , ProfiledDocument . class ) ;
}
@Override
@ -218,43 +230,128 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
return queue ;
}
@Override
public ProfiledDocument materialize ( String id ) {
throw new RuntimeException ( "TO IMPLEMENT" ) ;
}
@Override
public ProfiledDocument dematerialize ( String id ) {
throw new RuntimeException ( "TO IMPLEMENT" ) ;
public ProfiledDocument performStep ( String id , String step , Document options ) throws StepException , JsonProcessingException {
ExecutionReport report = step ( getByID ( id ) , step , options ) ;
return convert ( replace ( asDocument ( report . getResult ( ) ) , getCollectionName ( ) ) , ProfiledDocument . class ) ;
}
@Override
public ProfiledDocument index ( String id ) {
throw new RuntimeException ( "TO IMPLEMENT" ) ;
}
@Override
public ProfiledDocument deIndex ( String id ) {
throw new RuntimeException ( "TO IMPLEMENT" ) ;
}
/ * *
* NB Put at path :
*
*
*
* /
@Override
public ProfiledDocument performStep ( String id , String step , Document options ) {
throw new RuntimeException ( "TO IMPLEMENT" ) ;
public ProfiledDocument registerFileSet ( String id , String destination , Document attributes , List < TempFile > files ) throws ConfigurationException , StorageHubException , StorageException , StepException , JsonProcessingException {
log . info ( "Registering fileset [size : {}] for {} at {} with options {}" , files . size ( ) , id , destination , attributes ) ;
ProfiledDocument doc = getByID ( id ) ;
WorkspaceManager ws = new WorkspaceManager ( ) ;
StorageUtils storage = ImplementationProvider . get ( ) . getStorageProvider ( ) . getObject ( ) ;
log . debug ( "Checking {} path against profile {}" , destination , profile . getId ( ) ) ;
JSONPathWrapper schemaWrapper = new JSONPathWrapper ( profile . getSchema ( ) . toJson ( ) ) ;
List < Object > fieldDefinitions = schemaWrapper . getByPath ( destination ) ;
if ( fieldDefinitions = = null | | fieldDefinitions . isEmpty ( ) ) throw new WebApplicationException ( "No Field found in schema " + profile . getId ( ) + " at " + destination , Response . Status . BAD_REQUEST ) ;
if ( fieldDefinitions . size ( ) > 1 ) throw new WebApplicationException ( "Multiple field definitions (" + fieldDefinitions . size ( ) + ") found in " + profile . getId ( ) + " for " + destination , Response . Status . BAD_REQUEST ) ;
Field fieldDefinition = Serialization . convert ( fieldDefinitions . get ( 0 ) , Field . class ) ;
log . debug ( "Field definition is {}" , fieldDefinition ) ;
JSONPathWrapper docWrapper = new JSONPathWrapper ( doc . getTheDocument ( ) . toJson ( ) ) ;
List < RegisteredFileSet > found = docWrapper . getByPath ( destination , RegisteredFileSet . class ) ;
if ( fieldDefinition . getMaxCardinality ( ) = = 1 & & ( ! found . isEmpty ( ) ) ) {
throw new WebApplicationException ( "Cannot add registered fileset at " + destination + " : field is not collection." , Response . Status . BAD_REQUEST ) ;
}
RegisteredFileSet registeredFileSet = prepareRegisteredFileSet ( doc , profile , destination , attributes , files , storage , ws ) ;
log . debug ( "Registered fileset is {} " , registeredFileSet ) ;
if ( fieldDefinition . getMaxCardinality ( ) > 1 ) {
// Field is collection
found . add ( registeredFileSet ) ;
docWrapper . set ( destination , found ) ;
}
else {
docWrapper . set ( destination , registeredFileSet ) ;
}
log . debug ( "Setting result on profiled document" ) ;
doc . setTheDocument ( Document . parse ( docWrapper . getCtx ( ) . jsonString ( ) ) ) ;
doc = onUpdate ( doc ) ;
return convert ( replace ( asDocument ( doc ) , getCollectionName ( ) ) , ProfiledDocument . class ) ;
}
private ExecutionReport step ( ProfiledDocument theDocument , String step ) throws StepException {
log . info ( "[Profile {} ] Invoking Step {} on " , profile . getId ( ) , step , getManager ( ) . getDescriptor ( ) ) ;
// @Override
// public ProfiledDocument deleteRegisteredFileSet(String id, String destination, List<TempFile> files) {
// throw new RuntimeException("TO IMPLEMENT");
// }
private ExecutionReport step ( ProfiledDocument theDocument , String step , Document callParameters ) throws StepException {
log . info ( "[Profile {} ] Invoking Step {} on {}" , profile . getId ( ) , step , getManager ( ) . getDescriptor ( ) ) ;
StepExecutionRequest request = new StepExecutionRequest ( ) ;
request . setCallParameters ( callParameters ) ;
request . setDocument ( theDocument ) ;
request . setProfile ( profile ) ;
request . setStep ( StepExecutionRequest . Steps . ON_INIT_DOCUMENT ) ;
request . setStep ( step) ;
log . debug ( "Requesting Step Execution {} " , request ) ;
ExecutionReport report = getManager ( ) . performStep ( request ) ;
log . debug ( "Report is {}" , report ) ;
if ( report . getResult ( ) = = null ) throw new StepException ( "Report result is null" ) ;
return report ;
}
private static final RegisteredFileSet prepareRegisteredFileSet ( ProfiledDocument doc , Profile profile , String destination ,
Document attributes , List < TempFile > files , StorageUtils storage , WorkspaceManager ws ) throws StorageHubException , StorageException {
log . debug ( "Preparing Registered FileSet.." ) ;
attributes . putIfAbsent ( RegisteredFileSet . CREATION_INFO , UserUtils . getCurrent ( ) . asInfo ( ) ) ;
attributes . putIfAbsent ( RegisteredFileSet . ACCESS , doc . getInfo ( ) . getAccess ( ) ) ;
FolderContainer base = ws . createFolder ( new WorkspaceManager . FolderOptions (
doc . get_id ( ) , "Base Folder for profiled document. Profile " + profile . getId ( ) , null ) ) ;
FolderContainer sectionFolder = ws . createFolder ( new WorkspaceManager . FolderOptions (
doc . get_id ( ) + destination , "Registered Fileset at path " + destination , base ) ) ;
attributes . putIfAbsent ( RegisteredFileSet . FOLDER_ID , sectionFolder . getId ( ) ) ;
ArrayList < RegisteredFile > registeredFiles = new ArrayList < > ( ) ;
for ( TempFile f : files ) {
InputStream is = null ;
try {
log . debug ( "Opening temp file {}" , f ) ;
String fileUrl = storage . getURL ( f . getId ( ) ) ;
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 ) ;
}
}
attributes . putIfAbsent ( RegisteredFileSet . PAYLOADS , registeredFiles ) ;
return Serialization . convert ( attributes , RegisteredFileSet . class ) ;
}
}