package org.gcube.application.cms.plugins.implementations; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.gcube.application.cms.implementations.ProjectAccess; import org.gcube.application.cms.plugins.LifecycleManager; import org.gcube.application.cms.plugins.PluginManagerInterface; import org.gcube.application.cms.plugins.faults.*; import org.gcube.application.cms.plugins.implementations.executions.GuardedEventManager; import org.gcube.application.cms.plugins.implementations.executions.GuardedStepExecution; import org.gcube.application.cms.plugins.reports.EventExecutionReport; import org.gcube.application.cms.plugins.reports.InitializationReport; import org.gcube.application.cms.plugins.reports.Report; import org.gcube.application.cms.plugins.reports.StepExecutionReport; import org.gcube.application.cms.plugins.requests.BaseRequest; import org.gcube.application.cms.plugins.requests.EventExecutionRequest; import org.gcube.application.cms.plugins.requests.StepExecutionRequest; import org.gcube.application.geoportal.common.model.configuration.Configuration; import org.gcube.application.geoportal.common.model.document.accounting.User; import org.gcube.application.geoportal.common.model.document.lifecycle.LifecycleInformation; import org.gcube.application.geoportal.common.model.document.lifecycle.TriggeredEvents; import org.gcube.application.geoportal.common.model.plugins.LifecycleManagerDescriptor; import org.gcube.application.geoportal.common.model.plugins.OperationDescriptor; import org.gcube.application.geoportal.common.model.plugins.PluginDescriptor; import org.gcube.application.geoportal.common.model.rest.ConfigurationException; import org.gcube.application.geoportal.common.model.useCaseDescriptor.HandlerDeclaration; import org.gcube.application.geoportal.common.utils.ContextUtils; import java.util.HashMap; import java.util.Map; @Slf4j public abstract class AbstractLifeCycleManager extends AbstractPlugin implements LifecycleManager { protected static class Events{ public static final OperationDescriptor INIT=new OperationDescriptor(EventExecutionRequest.Events.ON_INIT_DOCUMENT,"Sets defaults and validate"); public static final OperationDescriptor UPDATE=new OperationDescriptor(EventExecutionRequest.Events.ON_UPDATE_DOCUMENT,"Sets defaults and validate"); public static final OperationDescriptor DELETE=new OperationDescriptor(EventExecutionRequest.Events.ON_DELETE_DOCUMENT,"No op"); public static final OperationDescriptor DELETE_FS=new OperationDescriptor(EventExecutionRequest.Events.ON_DELETE_FILESET,"No op"); } @Setter protected PluginManagerInterface pluginManager; @Setter protected ProjectAccess projectAccess; private Map registeredSteps=new HashMap<>(); private Map registeredEvent=new HashMap<>(); protected void setEvent(GuardedEventManager m){ OperationDescriptor op= m.getOp(); DESCRIPTOR.getSupportedEvents().put(op.getId(),op); registeredEvent.put(op.getId(),m); } protected void setStep(GuardedStepExecution e){ OperationDescriptor op= e.getOp(); DESCRIPTOR.getSupportedSteps().put(op.getId(),op); registeredSteps.put(op.getId(),e); } public AbstractLifeCycleManager() { DESCRIPTOR.setSupportedSteps(new HashMap<>()); DESCRIPTOR.setSupportedEvents(new HashMap<>()); registerEvents(); registerSteps(); } protected EventExecutionReport onDeleteDocument(EventExecutionReport report) throws ConfigurationException, InvalidPluginRequestException, MaterializationException, EventException {return report;} protected EventExecutionReport onDeleteFileSet(EventExecutionReport report) throws ConfigurationException, InvalidPluginRequestException, MaterializationException, EventException {return report;} protected EventExecutionReport onUpdateDocument(EventExecutionReport report){ report = validate(report); report = setDefault(report); return report; } protected EventExecutionReport onInitDocument(EventExecutionReport report) throws InvalidPluginRequestException { report = validate(report); report = setDefault(report); return report; } protected void registerEvents(){ setEvent(new GuardedEventManager(Events.INIT) { @Override protected EventExecutionReport run() throws Exception { return onInitDocument(theReport); } }); setEvent(new GuardedEventManager(Events.UPDATE) { @Override protected EventExecutionReport run() throws Exception { return onUpdateDocument(theReport); } }); setEvent(new GuardedEventManager(Events.DELETE) { @Override protected EventExecutionReport run() throws Exception { return onDeleteDocument(theReport); } }); setEvent(new GuardedEventManager(Events.DELETE_FS) { @Override protected EventExecutionReport run() throws Exception { return onDeleteFileSet(theReport); } }); } protected void registerSteps(){} protected LifecycleManagerDescriptor DESCRIPTOR=new LifecycleManagerDescriptor(";;;"); @Override public StepExecutionReport performStep(StepExecutionRequest request) throws StepException, InvalidPluginRequestException, InvalidProfileException, ConfigurationException, InsufficientPrivileges { log.info("Serving Request {}",request); log.debug("Checking is STEP {} is supported by {}",request.getStep(),DESCRIPTOR.getId()); if(!registeredSteps.containsKey(request.getStep())) throw new UnrecognizedStepException(("Invalid Step " + request.getStep())); HandlerDeclaration handlerDeclaration= getConfigurationFromProfile(request.getUseCaseDescriptor()); log.debug("Checking user role {} against config {} ",request.getCaller(),handlerDeclaration); if(!canInvokeStep(request.getStep(),request.getCaller(), handlerDeclaration)) throw new InsufficientPrivileges("User is not allowed to invoke "+request.getStep()); StepExecutionReport report=new StepExecutionReport(request); LifecycleInformation info=report.getToSetLifecycleInformation(); report.setStatus(Report.Status.OK); info.setLastOperationStatus(LifecycleInformation.Status.OK); info.setLastInvokedStep(request.getStep()); try { GuardedStepExecution exec=registeredSteps.get(request.getStep()); exec.setTheReport(report); exec.setHandlerConfiguration(handlerDeclaration); log.debug("Actually executing Step with {} ",exec); return exec.execute(); }catch (StepException | InvalidPluginRequestException e){ throw e; }catch (Throwable t) { log.error("Unable to perform step " + request.getStep(), t); String msg = "Unable to execute Step " + request.getStep() + ". Error was " + t.getMessage(); report.setStatus(Report.Status.ERROR); report.putMessage(msg); info.setLastOperationStatus(LifecycleInformation.Status.ERROR); info.addErrorMessage(msg); } return report; } protected boolean canInvokeStep(String stepID, User u, HandlerDeclaration config) throws ConfigurationException { return new RoleManager(config).canInvokeStep(stepID,u); } @Override public InitializationReport initInContext() throws InitializationException { InitializationReport report = new InitializationReport(); try{ report.setStatus(Report.Status.OK); } catch (Throwable e) { log.error("Unable to initialize plugins in {} ", ContextUtils.getCurrentScope(),e); report.setStatus(Report.Status.WARNING); report.putMessage("Unable to initialize plugins in "+ ContextUtils.getCurrentScope()+" : "+e.getMessage()); } return report; } @Override public InitializationReport init() throws InitializationException { InitializationReport report = new InitializationReport(); try{ report.setStatus(Report.Status.OK); } catch (Throwable e) { log.error("Unable to initialize plugins ",e); report.setStatus(Report.Status.WARNING); report.putMessage("Unable to initialize plugins : "+e.getMessage()); } return report; } @Override public PluginDescriptor getDescriptor() { return DESCRIPTOR; } @Override public EventExecutionReport onEvent(EventExecutionRequest request) throws EventException, InvalidPluginRequestException { log.info("Executing Event {}",request); EventExecutionReport report=new EventExecutionReport(request); report.getToSetLifecycleInformation().addEventReport(new TriggeredEvents()); TriggeredEvents info = report.getToSetLifecycleInformation().getLastEvent(); info.setLastOperationStatus(LifecycleInformation.Status.OK); info.setEvent(request.getEvent()); try { if(!registeredEvent.containsKey(request.getEvent())) throw new UnrecognizedEventException("Unexpected Event "+request.getEvent()); return registeredEvent.get(request.getEvent()).setTheReport(report).execute(); }catch (EventException e){ throw e; }catch (Throwable t){ log.error("Unable to execute on event "+request.getEvent(),t); String msg = "Unable to execute on event "+request.getEvent()+". Error was "+t.getMessage(); info.setLastOperationStatus(LifecycleInformation.Status.ERROR); info.addErrorMessage(msg); report.setStatus(Report.Status.ERROR); report.putMessage(msg); } return report; } /** * Override this method for programmatic default values management * * @param currentReport * @return */ public EventExecutionReport setDefault(EventExecutionReport currentReport){ // Default implementation is no op return currentReport; } public EventExecutionReport validate(EventExecutionReport currentReport){ // Default implementation is no op return currentReport; } @Override public void shutdown() throws ShutDownException {} @Override public Configuration getCurrentConfiguration(BaseRequest request) throws ConfigurationException { return new Configuration(); } }