Default 3Phase Manager

This commit is contained in:
Fabio Sinibaldi 2022-03-28 16:35:30 +02:00
parent 17839745aa
commit e2d728042f
18 changed files with 612 additions and 392 deletions

View File

@ -1,6 +0,0 @@
package org.gcube.application.cms.plugins;
public abstract class AbstractLifeCycleManager {
}

View File

@ -1,8 +1,6 @@
package org.gcube.application.cms.plugins;
import org.gcube.application.cms.plugins.faults.EventException;
import org.gcube.application.cms.plugins.faults.InvalidPluginRequestException;
import org.gcube.application.cms.plugins.faults.StepException;
import org.gcube.application.cms.plugins.faults.*;
import org.gcube.application.cms.plugins.reports.EventExecutionReport;
import org.gcube.application.cms.plugins.reports.StepExecutionReport;
import org.gcube.application.cms.plugins.requests.BaseRequest;
@ -17,7 +15,7 @@ public interface LifecycleManager extends InitializablePlugin{
// Lifecycle operations
public StepExecutionReport performStep(StepExecutionRequest request) throws StepException, InvalidPluginRequestException;
public StepExecutionReport performStep(StepExecutionRequest request) throws StepException, InvalidPluginRequestException, InvalidProfileException, ConfigurationException, InsufficientPrivileges;
public Configuration getCurrentConfiguration(BaseRequest request) throws ConfigurationException;

View File

@ -0,0 +1,22 @@
package org.gcube.application.cms.plugins.faults;
public class InsufficientPrivileges extends Exception {
public InsufficientPrivileges() {
}
public InsufficientPrivileges(String message) {
super(message);
}
public InsufficientPrivileges(String message, Throwable cause) {
super(message, cause);
}
public InsufficientPrivileges(Throwable cause) {
super(cause);
}
public InsufficientPrivileges(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@ -0,0 +1,120 @@
package org.gcube.application.cms.plugins.implementations;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
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.model.StepAccess;
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.cms.serialization.Serialization;
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.rest.ConfigurationException;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.HandlerDeclaration;
import org.gcube.application.geoportal.common.utils.ContextUtils;
import java.util.List;
@Slf4j
public abstract class AbstractLifeCycleManager extends AbstractPlugin implements LifecycleManager {
@Setter
protected PluginManagerInterface pluginManager;
@Override
public StepExecutionReport performStep(StepExecutionRequest request) throws StepException, InvalidPluginRequestException, InvalidProfileException, ConfigurationException, InsufficientPrivileges {
log.info("Serving Request {}",request);
StepExecutionReport report=new StepExecutionReport(request);
report.setStatus(Report.Status.OK);
if(!canInvokeStep(request.getStep(),request.getCaller(),
getConfigurationFromProfile(request.getUseCaseDescriptor())))
throw new InsufficientPrivileges("User is not allowed to invoke "+request.getStep());
LifecycleInformation info=report.getToSetLifecycleInformation();
info.setLastOperationStatus(LifecycleInformation.Status.OK);
info.setLastInvokedStep(request.getStep());
return report;
}
protected static boolean canInvokeStep(String stepID, User u, HandlerDeclaration config) throws ConfigurationException {
log.debug("Checking if {} can access STEP {}",u,stepID);
log.trace("Config is {}",config);
List l =config.getConfiguration().get("step_access", List.class);
if(l==null|| l.isEmpty()) throw new ConfigurationException("Missing Role management in UCD");
for (Object o : l) {
StepAccess a= Serialization.convert(o,StepAccess.class);
if(a.getStepId().equals(stepID)){
// found step ID
log.trace("Found Step ID declaration {} ",a);
for (String s : a.getRoles()) {
if (u.getRoles().contains(s))
return true;
}
}
}
return false;
}
@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 void shutdown() throws ShutDownException {}
@Override
public Configuration getCurrentConfiguration(BaseRequest request) throws ConfigurationException {
return new Configuration();
}
@Override
public EventExecutionReport onEvent(EventExecutionRequest request) throws EventException, InvalidPluginRequestException {
log.info("Executing Event {}",request);
EventExecutionReport report=new EventExecutionReport(request);
TriggeredEvents info=new TriggeredEvents();
info.setEvent(request.getEvent());
info.setLastOperationStatus(LifecycleInformation.Status.OK);
report.setStatus(Report.Status.OK);
report.getToSetLifecycleInformation().addEventReport(info);
return report;
}
}

View File

@ -1,5 +1,6 @@
package org.gcube.application.cms.plugins;
package org.gcube.application.cms.plugins.implementations;
import org.gcube.application.cms.plugins.Plugin;
import org.gcube.application.cms.plugins.faults.InvalidProfileException;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.HandlerDeclaration;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;
@ -7,7 +8,7 @@ import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDes
import java.util.List;
import java.util.Map;
public abstract class AbstractPlugin implements Plugin{
public abstract class AbstractPlugin implements Plugin {
@ -24,4 +25,6 @@ public abstract class AbstractPlugin implements Plugin{
else throw new InvalidProfileException("No Configuration found for "+getDescriptor().getId()+" in "+p.getId());
}
}

View File

@ -0,0 +1,323 @@
package org.gcube.application.cms.plugins.implementations;
import com.sun.xml.internal.xsom.impl.scd.Step;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.gcube.application.cms.plugins.IndexerPluginInterface;
import org.gcube.application.cms.plugins.MaterializationPlugin;
import org.gcube.application.cms.plugins.implementations.AbstractLifeCycleManager;
import org.gcube.application.cms.plugins.LifecycleManager;
import org.gcube.application.cms.plugins.faults.*;
import org.gcube.application.cms.plugins.model.PluginDescriptor;
import org.gcube.application.cms.plugins.model.StepAccess;
import org.gcube.application.cms.plugins.reports.*;
import org.gcube.application.cms.plugins.requests.*;
import org.gcube.application.cms.plugins.model.ComparableVersion;
import org.gcube.application.cms.serialization.Serialization;
import org.gcube.application.geoportal.common.model.configuration.Configuration;
import org.gcube.application.geoportal.common.model.configuration.Index;
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.rest.ConfigurationException;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.HandlerDeclaration;
import org.gcube.application.geoportal.common.utils.Files;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class Default3PhaseManager extends AbstractLifeCycleManager implements LifecycleManager {
private static class Phases {
public static final String PENDING_APPROVAL="Pending Approval";
public static final String PUBLISHED="PUBLISHED";
}
private static class STEPS{
public static final String SUBMIT="SUBMIT-FOR-REVIEW";
public static final String REJECT="REJECT-DRAFT";
public static final String APPROVE="APPROVE-SUBMITTED";
}
private static class PARAMETERS{
public static final String NOTES="notes";
}
protected PluginDescriptor DESCRIPTOR=new PluginDescriptor("DEFAULT-3PHASE", PluginDescriptor.BaseTypes.LIFECYCLE_MANAGER);
public Default3PhaseManager() {
DESCRIPTOR.setDescription("Default 3-phase lifecycle manager. This plugin supports a simple moderated publication lifecycle.");
DESCRIPTOR.setVersion(new ComparableVersion("1.0.0"));
}
protected static boolean canInvokeStep(String stepID, User u, HandlerDeclaration config) throws ConfigurationException {
List l =config.getConfiguration().get("step_access", List.class);
if(l==null|| l.isEmpty()) throw new ConfigurationException("Missing Role management in UCD");
boolean existingRule=false;
for (Object o : l) {
StepAccess a= Serialization.convert(o, StepAccess.class);
if(a.getStepId().equals(stepID)) {
existingRule = true;
log.trace("Found role {}",a);
for (String role : a.getRoles())
if (u.getRoles().contains(role))
return true;
}
}
if(!existingRule) throw new ConfigurationException("Missing step "+stepID+" access definition");
// nothing matches
return false;
}
@Override
public Configuration getCurrentConfiguration(BaseRequest req) throws ConfigurationException {
Configuration toReturn = super.getCurrentConfiguration(req);
toReturn.setIndexes(new ArrayList<>());
IndexerPluginInterface indexerPlugin;
indexerPlugin = (IndexerPluginInterface) pluginManager.getById("SDI-Indexer-Plugin");
BaseRequest indexRequest = new BaseRequest(req.getUseCaseDescriptor(),req.getCaller(),req.getContext());
// Info on Public index
try {
indexRequest.setCallParameters(getPublicIndexParams(req));
Index publicIndex = indexerPlugin.getIndex(indexRequest);
publicIndex.put("flag", "public");
toReturn.getIndexes().add(publicIndex);
}catch(ConfigurationException e){
toReturn.addErrorMessage("Unable to gather information on public GIS Centroids Index : "+e.getMessage());
log.error("Unable to gather information on public GIS Centroids Index",e);
}
// Info on internal_index
try {
indexRequest.setCallParameters(getInternalIndexParams(req));
Index internalIndex = indexerPlugin.getIndex(indexRequest);
internalIndex.put("flag", "internal");
toReturn.getIndexes().add(internalIndex);
}catch(ConfigurationException e){
toReturn.addErrorMessage("Unable to gather information on internal GIS Centroids Index : "+e.getMessage());
log.error("Unable to gather information on internal GIS Centroids Index",e);
}
return toReturn;
}
private Document getInternalIndexParams(BaseRequest req){
Document callParameters = new Document();
callParameters.put("workspace", Files.fixFilename(req.getUseCaseDescriptor().getId()+"_internal_"+req.getContext().getName()));
callParameters.put("indexName",Files.fixFilename(req.getUseCaseDescriptor().getId()+"_internal_"+req.getContext().getName()+"_centroids"));
return callParameters;
}
private Document getPublicIndexParams(BaseRequest req){
Document callParameters = new Document();
callParameters.put("workspace",Files.fixFilename(req.getUseCaseDescriptor().getId()+req.getContext().getName()));
callParameters.put("indexName",Files.fixFilename(req.getUseCaseDescriptor().getId()+req.getContext().getName()+"_centroids"));
return callParameters;
}
@Override
public EventExecutionReport onEvent(EventExecutionRequest request) throws EventException, InvalidPluginRequestException {
EventExecutionReport report=super.onEvent(request);
TriggeredEvents info = report.getToSetLifecycleInformation().getLastEvent();
try {
switch(request.getEvent()){
case EventExecutionRequest.Events.ON_INIT_DOCUMENT:
// Set Defaults as for on update
case EventExecutionRequest.Events.ON_UPDATE_DOCUMENT: {
log.debug("Setting default values..");
report=setDefault(report);
break;
}
case EventExecutionRequest.Events.ON_DELETE_DOCUMENT: {
//DELETE ALL
break;
}
default: throw new EventException("Unexpected Event "+request.getEvent());
}
}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
public StepExecutionReport performStep(StepExecutionRequest request) throws StepException, InvalidPluginRequestException, InvalidProfileException, ConfigurationException, InsufficientPrivileges {
StepExecutionReport report = super.performStep(request);
LifecycleInformation info=report.getToSetLifecycleInformation();
try {
if(!canInvokeStep(request.getStep(),request.getCaller(),getConfigurationFromProfile(request.getUseCaseDescriptor())))
throw new InsufficientPrivileges("Insufficient privileges for executing step "+request.getStep());
MaterializationPlugin plugin;
IndexerPluginInterface indexerPlugin;
plugin= (MaterializationPlugin) pluginManager.getById("SDI-Default-Materializer");
indexerPlugin = (IndexerPluginInterface) pluginManager.getById("SDI-Indexer-Plugin");
switch (request.getStep()) {
case STEPS.SUBMIT:{
//TODO validation
if(!request.getDocument().getLifecycleInformation().getPhase().equals(LifecycleInformation.DRAFT_PHASE))
throw new StepException("Document is not in "+LifecycleInformation.DRAFT_PHASE+" phase");
//Materialize layers
MaterializationRequest matReq = new MaterializationRequest(request.getUseCaseDescriptor(),request.getCaller(), request.getContext(), request.getDocument());
matReq.setDocument(request.getDocument());
matReq.setUseCaseDescriptor(request.getUseCaseDescriptor());
Document params = new Document();
String workspace = request.getUseCaseDescriptor().getId() + request.getContext().getId();
params.put("workspace", Files.fixFilename(workspace));
matReq.setCallParameters(params);
MaterializationReport matRep = plugin.materialize(matReq);
report.setResultingDocument(matRep.getResultingDocument());
switch(matRep.getStatus()){
case OK : {
index(report,indexerPlugin);
//TODO Optional Notifications
break;
}
case ERROR : {
info.setLastOperationStatus(LifecycleInformation.Status.ERROR);
matRep.getMessages().forEach(s -> info.addErrorMessage(s));
break;
}
case WARNING : {
info.setLastOperationStatus(LifecycleInformation.Status.WARNING);
matRep.getMessages().forEach(s -> info.addWarningMessage(s));
break;
}
}
}
break;
case STEPS.REJECT:{
if(!request.getDocument().getLifecycleInformation().getPhase().equals(Phases.PENDING_APPROVAL))
throw new StepException("Document is not in "+Phases.PENDING_APPROVAL+" phase");
// TODO OPTIONAL Notification
info.setPhase(Phases.PENDING_APPROVAL);
if(request.getCallParameters()!=null&&request.getCallParameters().containsKey(PARAMETERS.NOTES))
info.setNotes(request.getCallParameters().getString(PARAMETERS.NOTES));
break;
}
case STEPS.APPROVE:{
// Index-published
if(!request.getDocument().getLifecycleInformation().getPhase()
.equals(Phases.PENDING_APPROVAL))
throw new StepException("Document is not in "+Phases.PENDING_APPROVAL+" phase");
index(report,indexerPlugin);
break;
}
default:
throw new StepException("Invalid Step " + request.getStep());
}
}catch (StepException 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;
}
private IndexDocumentReport index(StepExecutionReport report,IndexerPluginInterface indexer) throws InvalidPluginRequestException {
StepExecutionRequest request = report.getTheRequest();
LifecycleInformation info=report.getToSetLifecycleInformation();
IndexDocumentRequest indexRequest = new IndexDocumentRequest(
request.getUseCaseDescriptor(),request.getCaller(), request.getContext(),request.getDocument());
indexRequest.setCallParameters(new Document());
if(request.getStep().equals(STEPS.APPROVE)) {
// public index
indexRequest.getCallParameters().putAll(getPublicIndexParams(request));
}
else {
// private index
indexRequest.getCallParameters().putAll(getPublicIndexParams(request));
}
IndexDocumentReport indexReport = indexer.index(indexRequest);
switch(indexReport.getStatus()){
case OK : {
if(request.getStep().equals(STEPS.APPROVE)) {
// public index
info.setPhase(Phases.PUBLISHED);
}
else {
// private index
info.setPhase(Phases.PENDING_APPROVAL);
}
report.setToSetSpatialReference(indexReport.getToSetSpatialReference());
break;
}
case ERROR : {
info.setLastOperationStatus(LifecycleInformation.Status.ERROR);
indexReport.getMessages().forEach(s -> info.addErrorMessage(s));
break;
}
case WARNING : {
info.setLastOperationStatus(LifecycleInformation.Status.WARNING);
indexReport.getMessages().forEach(s -> info.addWarningMessage(s));
break;
}
}
return indexReport;
}
/**
* Override this method for programmatic default values management
*
* @param currentReport
* @return
*/
public EventExecutionReport setDefault(EventExecutionReport currentReport){
// Default implementation is no op
return currentReport;
}
@Override
public PluginDescriptor getDescriptor() {
return DESCRIPTOR;
}
}

View File

@ -0,0 +1,29 @@
package org.gcube.application.cms.plugins.model;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;
@XmlRootElement
@AllArgsConstructor
@Getter
@Setter
@ToString(callSuper = true)
public class StepAccess {
public static final String STEP="STEP";
public static final String ROLES="roles";
@JsonProperty(STEP)
private String stepId;
@JsonProperty(ROLES)
private List<String> roles;
}

View File

@ -16,6 +16,6 @@ public class EventExecutionReport extends DocumentHandlingReport<EventExecutionR
@Override
public void setToSetLifecycleInformation(LifecycleInformation toSetLifecycleInformation) {
}
}

View File

@ -1,23 +1,19 @@
package org.gcube.application.cms.concessioni.plugins;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.bson.BsonDocument;
import org.bson.BsonString;
import org.bson.BsonValue;
import org.bson.Document;
import org.gcube.application.cms.plugins.IndexerPluginInterface;
import org.gcube.application.cms.plugins.MaterializationPlugin;
import org.gcube.application.cms.plugins.PluginManagerInterface;
import org.gcube.application.cms.plugins.*;
import org.gcube.application.cms.plugins.faults.*;
import org.gcube.application.cms.plugins.implementations.Default3PhaseManager;
import org.gcube.application.cms.plugins.model.ComparableVersion;
import org.gcube.application.cms.plugins.reports.*;
import org.gcube.application.cms.plugins.requests.*;
import org.gcube.application.cms.serialization.Serialization;
import org.gcube.application.cms.custom.gna.concessioni.model.ProfiledConcessione;
import org.gcube.application.cms.plugins.LifecycleManager;
import org.gcube.application.cms.plugins.model.PluginDescriptor;
import org.gcube.application.geoportal.common.model.configuration.Index;
import org.gcube.application.geoportal.common.model.document.*;
import org.gcube.application.geoportal.common.model.document.access.Access;
import org.gcube.application.geoportal.common.model.document.access.AccessPolicy;
@ -25,293 +21,30 @@ import org.gcube.application.geoportal.common.model.document.filesets.Registered
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.legacy.report.ConstraintCheck;
import org.gcube.application.geoportal.common.model.configuration.Configuration;
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;
import org.gcube.application.geoportal.common.utils.ContextUtils;
import org.gcube.application.geoportal.common.utils.Files;
import java.util.ArrayList;
@Slf4j
public class ConcessioniLifeCycleManager implements LifecycleManager {
private static class Phases {
public static final String PENDING_APPROVAL="Pending Approval";
}
/** Overrides 3 Phases lifecycle with override of default values
*
*/
public class ConcessioniLifeCycleManager extends Default3PhaseManager implements LifecycleManager {
private static final PluginDescriptor DESCRIPTOR=new PluginDescriptor("GNA-CONCESSIONI-LC", PluginDescriptor.BaseTypes.LIFECYCLE_MANAGER);
static {
public ConcessioniLifeCycleManager() {
DESCRIPTOR.setId("GNA-CONCESSIONI-LC");
DESCRIPTOR.setDescription("GNA Concessioni. This plugin supports custom lifecycle management for the GNA Concessioni UseCase.");
DESCRIPTOR.setVersion(new ComparableVersion("1.0.0"));
}
@Setter
PluginManagerInterface pluginManager;
@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 void shutdown() throws ShutDownException {
}
@Override
public StepExecutionReport performStep(StepExecutionRequest request) throws StepException, InvalidPluginRequestException {
log.info("Serving Request {}",request);
StepExecutionReport report=new StepExecutionReport(request);
report.setStatus(Report.Status.OK);
LifecycleInformation info=report.getToSetLifecycleInformation();
info.setLastOperationStatus(LifecycleInformation.Status.OK);
info.setLastInvokedStep(request.getStep());
try {
MaterializationPlugin plugin;
IndexerPluginInterface indexerPlugin;
plugin= (MaterializationPlugin) pluginManager.getById("SDI-Default-Materializer");
indexerPlugin = (IndexerPluginInterface) pluginManager.getById("SDI-Indexer-Plugin");
switch (request.getStep()) {
case "SUBMIT-FOR-REVIEW" :{
//TODO Checks
if(!request.getDocument().getLifecycleInformation().getPhase().equals(LifecycleInformation.DRAFT_PHASE))
throw new StepException("Document is not in Draft phase");
//Materialize layers
MaterializationRequest matReq = new MaterializationRequest(request.getUseCaseDescriptor(),request.getCaller(), request.getContext(), request.getDocument());
matReq.setDocument(request.getDocument());
matReq.setUseCaseDescriptor(request.getUseCaseDescriptor());
Document params = new Document();
String workspace = request.getUseCaseDescriptor().getId() + request.getContext().getId();
params.put("workspace", Files.fixFilename(workspace));
matReq.setCallParameters(params);
MaterializationReport matRep = plugin.materialize(matReq);
report.setResultingDocument(matRep.getResultingDocument());
switch(matRep.getStatus()){
case OK : {
info.setPhase(Phases.PENDING_APPROVAL);
//TODO Index-confidential
//TODO Notifications
break;
}
case ERROR : {
info.setLastOperationStatus(LifecycleInformation.Status.ERROR);
matRep.getMessages().forEach(s -> info.addErrorMessage(s));
break;
}
case WARNING : {
info.setLastOperationStatus(LifecycleInformation.Status.WARNING);
matRep.getMessages().forEach(s -> info.addWarningMessage(s));
break;
}
}
}
break;
case "REJECT-DRAFT":{
// Notification
// Set
break;
}
case "APPROVE DRAFT":{
// Index-published
if(!request.getDocument().getLifecycleInformation().getPhase()
.equals(Phases.PENDING_APPROVAL))
throw new StepException("Document is not in "+Phases.PENDING_APPROVAL+" phase");
IndexDocumentRequest indexRequest = new IndexDocumentRequest(request.getUseCaseDescriptor(),request.getCaller(), request.getContext(),request.getDocument());
Document callParameters = getPublicIndexParams(request);
indexRequest.setCallParameters(callParameters);
IndexDocumentReport indexReport = indexerPlugin.index(indexRequest);
switch(indexReport.getStatus()){
case OK : {
info.setPhase("PUBLISHED");
report.setToSetSpatialReference(indexReport.getToSetSpatialReference());
break;
}
case ERROR : {
info.setLastOperationStatus(LifecycleInformation.Status.ERROR);
indexReport.getMessages().forEach(s -> info.addErrorMessage(s));
break;
}
case WARNING : {
info.setLastOperationStatus(LifecycleInformation.Status.WARNING);
indexReport.getMessages().forEach(s -> info.addWarningMessage(s));
break;
}
}
break;
}
default:
throw new StepException("Invalid Step " + request.getStep());
}
}catch (StepException 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;
}
@Override
public EventExecutionReport onEvent(EventExecutionRequest request) throws EventException, InvalidPluginRequestException {
log.info("Executing Event {}",request);
EventExecutionReport report=new EventExecutionReport(request);
TriggeredEvents info=new TriggeredEvents();
info.setEvent(request.getEvent());
info.setLastOperationStatus(LifecycleInformation.Status.OK);
report.setStatus(Report.Status.OK);
try {
switch(request.getEvent()){
case EventExecutionRequest.Events.ON_INIT_DOCUMENT:
// Set Defaults as for on update
case EventExecutionRequest.Events.ON_UPDATE_DOCUMENT: {
log.debug("Setting default values..");
// TODO implement defaults for concessione
// report.setResult(setDefaults(request.getDocument()));
break;
}
case EventExecutionRequest.Events.ON_DELETE_DOCUMENT: {
//DELETE ALL
break;
}
default: throw new EventException("Unexpected Event "+request.getEvent());
}
}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);
}finally{
report.getToSetLifecycleInformation().addEventReport(info);
}
return report;
}
@Override
public Configuration getCurrentConfiguration(BaseRequest req) throws ConfigurationException {
Configuration toReturn = new Configuration();
toReturn.setIndexes(new ArrayList<>());
IndexerPluginInterface indexerPlugin;
indexerPlugin = (IndexerPluginInterface) pluginManager.getById("SDI-Indexer-Plugin");
BaseRequest indexRequest = new BaseRequest(req.getUseCaseDescriptor(),req.getCaller(),req.getContext());
// Info on Public index
try {
indexRequest.setCallParameters(getPublicIndexParams(req));
Index publicIndex = indexerPlugin.getIndex(indexRequest);
publicIndex.put("flag", "public");
toReturn.getIndexes().add(publicIndex);
}catch(ConfigurationException e){
toReturn.addErrorMessage("Unable to gather information on public GIS Centroids Index : "+e.getMessage());
log.error("Unable to gather information on public GIS Centroids Index",e);
}
// Info on internal_index
try {
indexRequest.setCallParameters(getInternalIndexParams(req));
Index internalIndex = indexerPlugin.getIndex(indexRequest);
internalIndex.put("flag", "internal");
toReturn.getIndexes().add(internalIndex);
}catch(ConfigurationException e){
toReturn.addErrorMessage("Unable to gather information on internal GIS Centroids Index : "+e.getMessage());
log.error("Unable to gather information on internal GIS Centroids Index",e);
}
return toReturn;
}
@Override
public PluginDescriptor getDescriptor() {
return DESCRIPTOR;
}
private Document getInternalIndexParams(BaseRequest req){
Document callParameters = new Document();
callParameters.put("workspace",Files.fixFilename(req.getUseCaseDescriptor().getId()+"_internal_"+req.getContext().getName()));
callParameters.put("indexName",Files.fixFilename(req.getUseCaseDescriptor().getId()+"_internal_"+req.getContext().getName()+"_centroids"));
return callParameters;
}
private Document getPublicIndexParams(BaseRequest req){
Document callParameters = new Document();
callParameters.put("workspace",Files.fixFilename(req.getUseCaseDescriptor().getId()+req.getContext().getName()));
callParameters.put("indexName",Files.fixFilename(req.getUseCaseDescriptor().getId()+req.getContext().getName()+"_centroids"));
return callParameters;
}
// STATIC ROUTINES
private static final Project setDefaults(Project document){
ProfiledConcessione c=Serialization.convert(document,ProfiledConcessione.class);
Document doc=c.getTheDocument();
Document doc=c.getTheDocument();
doc.putIfAbsent(ProfiledConcessione.SOGGETTO,new String[]{"Research Excavation","Archaeology"});
doc.putIfAbsent(ProfiledConcessione.DSCRIZIONE_CONTENUTO,"Relazione di fine scavo e relativo abstract; selezione di immagini rappresentative;"

View File

@ -21,6 +21,7 @@ public class LifecycleInformation {
public static final String ERROR_MESSAGES="_errorMessages";
public static final String WARNING_MESSAGES="_warningMessages";
public static final String TRIGGERED_EVENTS="_triggeredEvents";
public static final String NOTES="_notes";
public static enum Status{
OK,ERROR,WARNING
@ -38,6 +39,15 @@ public class LifecycleInformation {
private List<String> warningMessages;
@JsonProperty(TRIGGERED_EVENTS)
private List<TriggeredEvents> triggeredEvents;
@JsonProperty(NOTES)
private String notes;
@JsonIgnore
public TriggeredEvents getLastEvent(){
if(triggeredEvents==null || triggeredEvents.isEmpty()) return null;
return triggeredEvents.get(triggeredEvents.size()-1);
}
@JsonIgnore
public LifecycleInformation addErrorMessage(String msg){

View File

@ -15,7 +15,7 @@ import java.util.Map;
@Getter
@Setter
@ToString(callSuper = true)
public class Field extends Document {
public class Field extends Document {
public static final String TYPE="_type";
public static final String CHILDREN="_children";

View File

@ -12,7 +12,7 @@ public class GCubeTest {
// testContext = "/pred4s/preprod/preVRE";
// testContext = "/gcube/devsec/devVRE";
testContext = "/gcube/devsec/devVRE";
System.out.println("TEST CONTEXT = "+testContext);

View File

@ -1,79 +0,0 @@
package org.gcube.application.geoportal.service.engine.handlers;
import lombok.extern.slf4j.Slf4j;
import org.gcube.application.cms.plugins.LifecycleManager;
import org.gcube.application.cms.plugins.PluginManagerInterface;
import org.gcube.application.cms.plugins.faults.EventException;
import org.gcube.application.cms.plugins.faults.InitializationException;
import org.gcube.application.cms.plugins.faults.ShutDownException;
import org.gcube.application.cms.plugins.faults.StepException;
import org.gcube.application.cms.plugins.model.PluginDescriptor;
import org.gcube.application.cms.plugins.reports.EventExecutionReport;
import org.gcube.application.cms.plugins.reports.StepExecutionReport;
import org.gcube.application.cms.plugins.reports.InitializationReport;
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.cms.plugins.model.ComparableVersion;
import org.gcube.application.geoportal.common.model.configuration.Configuration;
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.UseCaseDescriptor;
@Slf4j
public class SimpleLifeCycleManager implements LifecycleManager {
private static final PluginDescriptor DESCRIPTOR=new PluginDescriptor("SIMPLE-LIFECYCLE", "Simple Lifecycle manager");
static {
DESCRIPTOR.setDescription("Simple Lifecycle Management. This plugin supports a simple publication lifecycle.");
DESCRIPTOR.setVersion(new ComparableVersion("1.0.0"));
}
@Override
public InitializationReport initInContext() throws InitializationException {
return null;
}
@Override
public InitializationReport init() throws InitializationException {
return null;
}
@Override
public void shutdown() throws ShutDownException {
}
@Override
public StepExecutionReport performStep(StepExecutionRequest request) throws StepException {
log.info("Received Request ");
switch(request.getStep()){
default : throw new StepException("Invalid Step "+request.getStep());
}
//throw new StepException("Still to implement");
}
@Override
public Configuration getCurrentConfiguration(BaseRequest ucd) throws ConfigurationException {
return null;
}
@Override
public EventExecutionReport onEvent(EventExecutionRequest request) throws EventException {
return null;
}
@Override
public void setPluginManager(PluginManagerInterface manager) {
}
@Override
public PluginDescriptor getDescriptor() {
return null;
}
}

View File

@ -6,6 +6,7 @@ import com.mongodb.client.model.FindOneAndReplaceOptions;
import com.mongodb.client.model.FindOneAndUpdateOptions;
import com.mongodb.client.model.ReturnDocument;
import com.vdurmont.semver4j.Semver;
import jdk.nashorn.internal.runtime.regexp.joni.Config;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
@ -13,6 +14,7 @@ import org.bson.Document;
import org.bson.types.ObjectId;
import org.gcube.application.cms.plugins.LifecycleManager;
import org.gcube.application.cms.plugins.faults.EventException;
import org.gcube.application.cms.plugins.faults.InsufficientPrivileges;
import org.gcube.application.cms.plugins.faults.StepException;
import org.gcube.application.cms.plugins.model.PluginDescriptor;
import org.gcube.application.cms.plugins.reports.DocumentHandlingReport;
@ -405,21 +407,23 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
@Override
public Project performStep(String id, String step, Document options) throws StepException, JsonProcessingException, ProjectLockedException, ProjectNotFoundException, InvalidLockException, InvalidUserRoleException, UnauthorizedAccess {
Project document = lock(id,"Step "+step+" execution");
try{
try {
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);
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) {
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(document,u)) throw new UnauthorizedAccess("No edit rights on project "+id);
if (!policy.canWrite(document, u)) throw new UnauthorizedAccess("No edit rights on project " + id);
document.getLifecycleInformation().cleanState();
document = step(document, step, options);
}catch (InsufficientPrivileges | ConfigurationException e){
throw e;
} catch(Throwable t){
log.error("[UseCaseDescriptor {} ] ERROR Invoking Step {} on document {}" , useCaseDescriptor.getId(),step,id,t);
LifecycleInformation info = new LifecycleInformation();
@ -649,20 +653,20 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
}
private Project step(Project theDocument, String step, Document callParameters){
try{
log.info("[UseCaseDescriptor {}] Invoking Step {} on {}" , useCaseDescriptor.getId(),step,getManager().getDescriptor());
AccountingInfo user= UserUtils.getCurrent().asInfo();
private Project step(Project theDocument, String step, Document callParameters) throws InsufficientPrivileges, ConfigurationException {
try {
log.info("[UseCaseDescriptor {}] Invoking Step {} on {}", useCaseDescriptor.getId(), step, getManager().getDescriptor());
AccountingInfo user = UserUtils.getCurrent().asInfo();
StepExecutionRequest request=new StepExecutionRequest(useCaseDescriptor,user.getUser(),user.getContext(),theDocument,step);
StepExecutionRequest request = new StepExecutionRequest(useCaseDescriptor, user.getUser(), user.getContext(), theDocument, step);
log.debug("Requesting Step Execution {}",request);
StepExecutionReport report= getManager().performStep(request);
Project toReturn = report.prepareResult();
log.debug("Requesting Step Execution {}", request);
StepExecutionReport report = getManager().performStep(request);
Project toReturn = report.prepareResult();
// EVENTS
if(report.getToTriggerEvents()!=null) {
// EVENTS
if (report.getToTriggerEvents() != null) {
Iterator<EventExecutionRequest> eventIT = report.getToTriggerEvents().listIterator();
while (!toReturn.getLifecycleInformation().getLastOperationStatus().equals(LifecycleInformation.Status.ERROR)
&& eventIT.hasNext()) {
@ -672,8 +676,8 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
}
}
// STEPS
if(report.getCascadeSteps()!=null) {
// STEPS
if (report.getCascadeSteps() != null) {
Iterator<StepExecutionRequest> stepIT = report.getCascadeSteps().listIterator();
while (!toReturn.getLifecycleInformation().getLastOperationStatus().equals(LifecycleInformation.Status.ERROR)
&& stepIT.hasNext()) {
@ -682,7 +686,9 @@ public class ProfiledMongoManager extends MongoManager implements MongoManagerI<
toReturn = step(toReturn, triggerRequest.getStep(), triggerRequest.getCallParameters());
}
}
return report.prepareResult();
return report.prepareResult();
}catch (InsufficientPrivileges | ConfigurationException e){
throw e;
}catch(Throwable t){
log.error("Unable to perform step "+step,t);
theDocument.getLifecycleInformation().addErrorMessage("Unable to perform step "+step+" cause : "+ t.getMessage());

View File

@ -0,0 +1,42 @@
package org.gcube.application.geoportal.service.profiledDocuments;
import org.gcube.application.geoportal.common.model.useCaseDescriptor.DataAccessPolicy;
import org.gcube.application.geoportal.common.rest.InterfaceConstants;
import org.junit.Test;
import javax.ws.rs.client.WebTarget;
public class RolesTests extends AbstractProfiledDocumentsTests{
@Override
protected WebTarget baseTarget() {
String testProfileId="rolesTesting";
return target(InterfaceConstants.Methods.PROJECTS).path(testProfileId);
}
@Test
private void testRoles(){
// Insert for each
}
private void test(String role, DataAccessPolicy.Policy expected){
// Collect behaviour
// try access not owned
// check against expected.getRead()
// try access owned
// check against expected.getRead()
// try access any
// check against expected.getRead()
// Try create
// check against expected.getWrite()
// Try edit owned
// check against expected.getWrite()
// Try edit not owned
// check against expected.getWrite()
}
}

View File

@ -0,0 +1,20 @@
{
"_id" : "rolesTesting",
"_version" : "1.0.0",
"_name" : "Roles Testing",
"_description" : "Simple uC for roles management testing",
"_schema" : {},
"_creationInfo": {
"_user" : {
"_username": "fabio.sinibaldi"
}
},
"_data_access_policy" : [
{"_policy" : {"_read" : "own", "_write" : "own"}, "_roles":[]},
{"_policy" : {"_read" : "any", "_write" : "none"}, "_roles":["Guest"],
"_enforcer": {"_filter" : {"_lifecycleInformation._phase" : {"$eq" : "Published"}}}},
{"_policy" : {"_read" : "any", "_write" : "none"}, "_roles":["Admin"]},
{"_policy" : {"_read" : "any", "_write" : "any"}, "_roles":["Data-Manager"]}
],
"_handlers" : []
}

View File

@ -5,7 +5,7 @@ import lombok.extern.slf4j.Slf4j;
import org.gcube.application.cms.caches.AbstractScopedMap;
import org.gcube.application.cms.implementations.ISInterface;
import org.gcube.application.cms.implementations.ImplementationProvider;
import org.gcube.application.cms.plugins.AbstractPlugin;
import org.gcube.application.cms.plugins.implementations.AbstractPlugin;
import org.gcube.application.cms.plugins.InitializablePlugin;
import org.gcube.application.cms.plugins.faults.InitializationException;
import org.gcube.application.cms.plugins.faults.ShutDownException;
@ -15,7 +15,6 @@ import org.gcube.application.cms.sdi.engine.PostgisIndexer;
import org.gcube.application.cms.sdi.engine.SDIManagerWrapper;
import org.gcube.application.geoportal.common.model.rest.ConfigurationException;
import org.gcube.application.geoportal.common.model.rest.DatabaseConnection;
import org.gcube.application.geoportal.common.utils.ContextUtils;
import java.time.Duration;
import java.time.temporal.ChronoUnit;

View File

@ -4,7 +4,7 @@ import lombok.Data;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.gcube.application.cms.plugins.AbstractPlugin;
import org.gcube.application.cms.plugins.implementations.AbstractPlugin;
import org.gcube.application.cms.plugins.faults.InvalidPluginRequestException;
import org.gcube.application.cms.sdi.engine.SDIManagerWrapper;
import org.gcube.application.cms.sdi.faults.SDIInteractionException;