package org.gcube.application.cms.sdi.plugins; import com.vdurmont.semver4j.Semver; import lombok.Data; import lombok.Synchronized; import lombok.extern.slf4j.Slf4j; import org.bson.Document; import org.gcube.application.cms.plugins.MaterializationPlugin; import org.gcube.application.cms.plugins.faults.InitializationException; import org.gcube.application.cms.plugins.faults.InvalidPluginRequestException; import org.gcube.application.cms.plugins.faults.MaterializationException; import org.gcube.application.cms.plugins.faults.ShutDownException; import org.gcube.application.cms.plugins.implementations.AbstractPlugin; import org.gcube.application.cms.plugins.model.ComparableVersion; import org.gcube.application.geoportal.common.model.plugins.MaterializerPluginDescriptor; import org.gcube.application.geoportal.common.model.plugins.PluginDescriptor; import org.gcube.application.cms.plugins.reports.InitializationReport; import org.gcube.application.cms.plugins.reports.MaterializationReport; import org.gcube.application.cms.plugins.reports.Report; import org.gcube.application.cms.plugins.requests.MaterializationRequest; import org.gcube.application.cms.sdi.engine.SDIManagerWrapper; import org.gcube.application.cms.sdi.faults.SDIInteractionException; import org.gcube.application.cms.serialization.Serialization; import org.gcube.application.geoportal.common.model.JSONPathWrapper; import org.gcube.application.geoportal.common.model.document.Project; import org.gcube.application.geoportal.common.model.document.filesets.Materialization; import org.gcube.application.geoportal.common.model.document.filesets.RegisteredFileSet; import org.gcube.application.geoportal.common.model.document.filesets.sdi.GCubeSDILayer; import org.gcube.application.geoportal.common.model.useCaseDescriptor.Field; import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor; import org.gcube.application.geoportal.common.utils.ContextUtils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @Slf4j public class SDIMaterializerPlugin extends AbstractPlugin implements MaterializationPlugin { @Data public static class MaterializationConfig{ private String schemaField; private String documentPath; } Map sdiManagerMap=null; private SDIManagerWrapper getSDIManager(){ return sdiManagerMap.get(ContextUtils.getCurrentScope()); } @Override @Synchronized public InitializationReport initInContext() throws InitializationException { InitializationReport report = new InitializationReport(); try{ String context = ContextUtils.getCurrentScope(); if(getSDIManager()==null) { log.info("Initializing in " + context); sdiManagerMap.put(context,new SDIManagerWrapper()); } report.setStatus(Report.Status.OK); report.putMessage("Initialized SDI Manager in "+context+" pointing to "+getSDIManager().getGeoserverHostName()); } catch (SDIInteractionException e) { throw new InitializationException("Unable to initialize SDI Manager ",e); } return report; } @Override @Synchronized public InitializationReport init() throws InitializationException { InitializationReport report = new InitializationReport(); sdiManagerMap=new HashMap<>(); report.setStatus(Report.Status.OK); return report; } @Override public void shutdown() throws ShutDownException { } /** * Expected params : * -workspace MANDATORY * -titleField * * @param request * @return * @throws MaterializationException */ @Override public MaterializationReport materialize(MaterializationRequest request) throws MaterializationException, InvalidPluginRequestException { log.info("Materializer {} : Performing {} ",this.getDescriptor().getId(),request); Project project =request.getDocument(); UseCaseDescriptor useCaseDescriptor = request.getUseCaseDescriptor(); Document requestArguments=request.getCallParameters(); MaterializationReport report= new MaterializationReport(request); try{ Document profileConfiguration =getConfigurationFromProfile(useCaseDescriptor).getConfiguration(); log.debug("UseCaseDescriptor Configuration is {} ",profileConfiguration); JSONPathWrapper documentNavigator=new JSONPathWrapper(project.getTheDocument().toJson()); JSONPathWrapper schemaNavigator=new JSONPathWrapper(useCaseDescriptor.getSchema().toJson()); for(Object fsConfigObj : profileConfiguration.get("registeredFileSetPaths", List.class)){ log.debug("Managing {} ",fsConfigObj); MaterializationConfig fsConfig=Serialization.convert(fsConfigObj,MaterializationConfig.class); List matchingFieldDefinitions =schemaNavigator.getByPath(fsConfig.getSchemaField()); if(matchingFieldDefinitions==null || matchingFieldDefinitions.isEmpty()) throw new MaterializationException("Invalid Field Definition path in configuration [NO MATCH] : "+ fsConfig.getSchemaField()); if(matchingFieldDefinitions.size()>1) throw new MaterializationException("Invalid Field Definition path in configuration [MATCHES "+matchingFieldDefinitions.size()+"] : "+ fsConfig.getSchemaField()); Field f = Serialization.convert(matchingFieldDefinitions.get(0),Field.class); // TODO Check if schema points to RegisteredFileSet for(Object fsObject : documentNavigator.getByPath(fsConfig.getDocumentPath())){ RegisteredFileSet fs = Serialization.convert(fsObject,RegisteredFileSet.class); log.debug("Found {} ",fs); requestArguments.putIfAbsent("basePersistencePath", useCaseDescriptor.getId()); requestArguments.putIfAbsent("documentID", project.getId()); if(requestArguments.containsKey("titleField")) requestArguments.putIfAbsent("layerTitle",fs.getString(requestArguments.getString("titleField"))); else requestArguments.putIfAbsent("layerTitle",fs.getUUID()); //Add FS uuid at ws_baseName requestArguments.put("workspace",request.getMandatory("workspace")+"_"+ project.getId()); // Actually materializing RegisteredFileSet obtained = getSDIManager().materializeLayer(fs,requestArguments); log.debug("Obtained {} ",obtained); documentNavigator.setElement("$..[?(@."+ RegisteredFileSet.UUID+" == '"+fs.getUUID()+"')]",obtained); } } String finalDocument = documentNavigator.getValueCTX().jsonString(); log.debug("Final document after materialization is {} ",finalDocument); report.setResultingDocument(Document.parse(finalDocument)); report.setStatus(Report.Status.OK); }catch (SDIInteractionException e){ log.error("Unable to materialize "+request,e); report.setStatus(Report.Status.ERROR); report.putMessage(e.getMessage()); }catch (Throwable t){ log.error("Unable to materialize "+request,t); report.setStatus(Report.Status.ERROR); report.putMessage(t.getMessage()); }finally{ return report; } } /** * Expected parameters * - fileSetPath * * @param request * @return * @throws MaterializationException * @throws InvalidPluginRequestException */ @Override public MaterializationReport dematerialize(MaterializationRequest request) throws MaterializationException, InvalidPluginRequestException { log.info("Serving DeMaterialization {} ",request); MaterializationReport report= new MaterializationReport(request); try{ SDIManagerWrapper sdi=getSDIManager(); JSONPathWrapper wrapper = new JSONPathWrapper(request.getDocument().getTheDocument().toJson()); for(String s : wrapper.getMatchingPaths(request.getMandatory("fileSetPath"))){ log.debug("Found matching {} ",s); RegisteredFileSet registeredFileSet=Serialization.convert(wrapper.getByPath(s).get(0),RegisteredFileSet.class); List toKeep = new ArrayList<>(); for(Object matObj : registeredFileSet.getMaterializations()){ Materialization mat = Serialization.convert(matObj,Materialization.class); if(mat.getType().equals(GCubeSDILayer.GCUBE_SDY_LAYER_TYPE)) { log.debug("Deleting Layer {} ",mat); sdi.deleteLayer(Serialization.convert(matObj, GCubeSDILayer.class)); }else toKeep.add(matObj); } // Resetting remaining materializations registeredFileSet.put(RegisteredFileSet.MATERIALIZATIONS,toKeep); // Update FS in doc wrapper.setElement(s,registeredFileSet); } // Resetting Document report.setResultingDocument(Serialization.asDocument(wrapper.getValueCTX().jsonString())); }catch (SDIInteractionException e){ log.error("Unable to materialize "+request,e); report.setStatus(Report.Status.ERROR); report.putMessage(e.getMessage()); }catch (Throwable t){ log.error("Unable to materialize "+request,t); report.setStatus(Report.Status.ERROR); report.putMessage(t.getMessage()); }finally{ return report; } } private static final PluginDescriptor DESCRIPTOR=new PluginDescriptor("SDI-Default-Materializer", MaterializerPluginDescriptor.MATERIALIZER); static { DESCRIPTOR.setDescription("SDI Materializer. " + "This plugin materialize FileSets in gCube SDI."); DESCRIPTOR.setVersion(new Semver("1.0.0")); } @Override public PluginDescriptor getDescriptor() { return DESCRIPTOR; } }