package org.gcube.application.geoportal.service.engine.mongo; import com.fasterxml.jackson.core.JsonProcessingException; import com.mongodb.client.MongoDatabase; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; import org.bson.Document; import org.bson.types.ObjectId; import org.gcube.application.cms.plugins.LifecycleManager; 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.model.document.*; import org.gcube.application.geoportal.common.model.legacy.Concessione; import org.gcube.application.geoportal.common.model.legacy.report.ValidationReport; 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.service.engine.ImplementationProvider; import org.gcube.application.geoportal.service.engine.providers.PluginManager; import org.gcube.application.geoportal.service.model.internal.faults.ConfigurationException; import org.gcube.application.geoportal.service.model.internal.faults.DeletionException; import org.gcube.application.geoportal.service.utils.Serialization; import org.gcube.application.geoportal.service.utils.UserUtils; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import java.io.IOException; import java.security.InvalidParameterException; import java.util.List; import java.util.Map; import java.util.concurrent.LinkedBlockingQueue; import java.util.function.Consumer; import static org.gcube.application.geoportal.service.engine.mongo.ConcessioniMongoManager.asConcessione; @Slf4j public class ProfiledMongoManager extends MongoManager implements MongoManagerI{ Profile profile; MongoDatabase db=null; LifecycleManager lfManager; public ProfiledMongoManager(String profileId) throws ConfigurationException { // Check Profile ID log.info("Loading profile ID {} ",profileId); if(profileId==null) throw new InvalidParameterException("Profile ID cannot be null"); Map profiles=ImplementationProvider.get().getProfiles().getObject(); if(!profiles.containsKey(profileId)) { log.debug("Asked profile {} not found. Available ones are {} ",profileId,profiles.keySet()); throw new WebApplicationException("Profile " + profileId + " not registered", Response.Status.NOT_FOUND); } profile=profiles.get(profileId); log.debug("Loaded Profile {} ",profile); //Getting Lifecycle Manager declaration from Profile List handlerDeclarations= profile.getHandlersMap().get(PluginDescriptor.BaseTypes.LIFECYCLE_MANAGER); if(handlerDeclarations==null || handlerDeclarations.isEmpty()) throw new ConfigurationException("No Lifecycle Handler defined for profile ID "+profileId); if(handlerDeclarations.size()>1) throw new ConfigurationException("Too many Lifecycle Handlers defined ("+handlerDeclarations+") in profile ID "+profileId); HandlerDeclaration lcHandlerDeclaration=handlerDeclarations.get(0); // Loading Lifecycle Manager log.debug("Looking for handler {} ",lcHandlerDeclaration); try{ lfManager=(LifecycleManager) ImplementationProvider.get().getPluginManager().getObject().get(lcHandlerDeclaration.getId()); if(lfManager==null) throw new ConfigurationException("Unable to find Lifecycle Manager Plugin. ID "+lcHandlerDeclaration.getId()); }catch(ClassCastException e){ throw new ConfigurationException("Unable to use "+lcHandlerDeclaration.getId()+" as Lifecycle Manager"); } // Connect to DB String toUseDB=super.client.getConnection().getDatabase(); log.info("Connecting to DB {} ",toUseDB); // TODO MAP OF DATABASES? db=client.getTheClient().getDatabase(toUseDB); } 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 return profile.getId(); } @Override public MongoDatabase getDatabase(){ return db; } @Override public ProfiledDocument registerNew(Document toRegisterDoc) throws IOException, StepException { log.info("Registering new document in {} ",profile.getId()); log.debug("Going to register {}",toRegisterDoc.toJson()); ProfiledDocument toRegister = new ProfiledDocument(); toRegister.setTheDocument(toRegisterDoc); PublicationInfo pubInfo=new PublicationInfo(); pubInfo.setCreationInfo(UserUtils.getCurrent().asInfo()); // TODO Set Access From Profile Access access=new Access(); access.setLicense(""); access.setPolicy(AccessPolicy.OPEN); pubInfo.setAccess(access); toRegister.setInfo(pubInfo); toRegister.setProfileID(profile.getId()); toRegister.setProfileVersion(profile.getVersion()); toRegister.setVersion(new ComparableVersion("1.0.0")); // Apply Lifecycle toRegister=step(toRegister,StepExecutionRequest.Steps.ON_INIT_DOCUMENT).getResult(); log.debug("Going to register {} ",toRegister); // Insert object ObjectId id =insert(asDocument(toRegister),getCollectionName()); log.info("Obtained id {} ",id); return getByID(id.toHexString()); } @Override public ProfiledDocument update(String id, ProfiledDocument toSet) throws IOException, StepException { log.trace("Replacing {} ",toSet); toSet=onUpdate(toSet); return asProfiledDocument(replace(asDocument(toSet),getCollectionName())); } @Override public void delete(String id,boolean force) throws DeletionException { log.debug("Deleting by ID {}, force {}",id,force); try{ ProfiledDocument doc =getByID(id); // TODO INVOKE LIFECYCLE //if(!force&&isPublished(id)) throw new Exception("Cannot delete published documents. Unpublish it or use force = true"); try{ // TODO CHECK PHASE AND STATUS // DEINDEX // DEMATERIALIZE // DELETE CONTENT // DELETE ENTRY throw new DeletionException("IMPLEMENT THIS"); // delete(asId(id), getCollectionName()); }catch(DeletionException e) { //storing updated - partially deleted // concessione=onUpdate(concessione); // replace(asDocument(concessione), collectionName); throw e; } }catch(Throwable t){ throw new DeletionException("Unable to delete "+id,t); } } @Override public ProfiledDocument getByID(String id) throws IOException { return asProfiledDocument(super.getById(asId(id),getCollectionName())); } @Override public Iterable query(QueryRequest queryRequest) { log.info("Querying {} ",queryRequest); LinkedBlockingQueue queue=new LinkedBlockingQueue(); query(queryRequest,getCollectionName()).forEach( (Consumer) (Document d)->{try{ queue.put(d); }catch(Throwable t){log.warn("Unable to translate "+d);}}); log.info("Returned {} elements ",queue.size()); return queue; } @Override public Iterable filter(QueryRequest queryRequest) { log.info("Searching concessione for filter {} ",queryRequest); LinkedBlockingQueue queue=new LinkedBlockingQueue(); query(queryRequest,getCollectionName()).forEach( (Consumer) (Document d)->{try{ queue.put(d); }catch(Throwable t){log.warn("Unable to translate "+d);}}); log.info("Returned {} elements ",queue.size()); return queue; } @Override public ProfiledDocument materialize(String id) { throw new RuntimeException("TO IMPLEMENT"); } @Override public ProfiledDocument dematerialize(String id) { throw new RuntimeException("TO IMPLEMENT"); } @Override public ProfiledDocument index(String id) { throw new RuntimeException("TO IMPLEMENT"); } @Override public ProfiledDocument deIndex(String id) { throw new RuntimeException("TO IMPLEMENT"); } @Override public ProfiledDocument performStep(String id, String step, Document options) { throw new RuntimeException("TO IMPLEMENT"); } private ExecutionReport step(ProfiledDocument theDocument,String step) throws StepException { log.info("[Profile {} ] Invoking Step {} on " ,profile.getId(),step,lfManager.getDescriptor()); StepExecutionRequest request=new StepExecutionRequest(); request.setDocument(theDocument); request.setProfile(profile); request.setStep(StepExecutionRequest.Steps.ON_INIT_DOCUMENT); log.debug("Requesting Step Execution {} ",request); return lfManager.performStep(request); } }