package ee.telekom.workflow.graph.node.activity; import javax.el.ELProcessor; import ee.telekom.workflow.graph.Environment; import ee.telekom.workflow.graph.GraphEngine; import ee.telekom.workflow.graph.GraphInstance; import ee.telekom.workflow.graph.Token; import ee.telekom.workflow.graph.WorkflowException; import ee.telekom.workflow.graph.el.ElUtil; import ee.telekom.workflow.graph.node.AbstractNode; /** * Activity validating an attribute in the {@link GraphInstance}'s {@link Environment}. * * For a required attribute, it checks that the attribute's value is set in the environment (possibly also to <code>null</code>) * and that this value is assignable to the defined type. * For an optional attribute, it initialises the value to a default, if it is not yet set in the environment and ensures that * its value is assignable to the defined type. */ public class ValidateAttributeActivity extends AbstractNode{ private String attribute; private boolean isRequired; private Class<?> type; private Object defaultValue; public ValidateAttributeActivity( int id, String attribute, Class<?> type ){ this( id, null, attribute, type, true, null ); } public ValidateAttributeActivity( int id, String attribute, Class<?> type, boolean isRequired ){ this( id, null, attribute, type, isRequired, null ); } public ValidateAttributeActivity( int id, String attribute, Class<?> type, boolean isRequired, Object defaultValue ){ this( id, null, attribute, type, isRequired, defaultValue ); } public ValidateAttributeActivity( int id, String name, String attribute, Class<?> type, boolean isRequired, Object defaultValue ){ super( id, name ); this.attribute = attribute; this.type = type; this.isRequired = isRequired; this.defaultValue = defaultValue; } public String getAttribute(){ return attribute; } public boolean isRequired(){ return isRequired; } public Class<?> getType(){ return type; } public Object getDefaultValue(){ return defaultValue; } @Override public void execute( GraphEngine engine, Token token ){ GraphInstance instance = token.getInstance(); Environment environment = instance.getEnvironment(); if( !environment.containsAttribute( attribute ) ){ if( isRequired ){ // Throw exception throw new WorkflowException( "Missing required attribute '" + attribute + "'" ); } else{ // Use default value if( defaultValue instanceof String && ElUtil.hasBrackets( (String)defaultValue ) ){ ELProcessor processor = ElUtil.initNewELProcessor( environment, instance.getExternalId() ); Object expressionResult = processor.eval( ElUtil.removeBrackets( (String)defaultValue ) ); environment.setAttribute( attribute, expressionResult ); } else{ environment.setAttribute( attribute, defaultValue ); } } } // Validate type of value Object value = environment.getAttribute( attribute ); if( value != null && !type.isAssignableFrom( value.getClass() ) ){ throw new WorkflowException( "The value of attribute '" + attribute + "' is of type " + value.getClass().getCanonicalName() + " whis is not assignable to the expected type " + type.getCanonicalName() ); } engine.complete( token, null ); } @Override public void cancel( GraphEngine engine, Token token ){ // Tokens cannot "wait" at this kind of node since the execution // is synchronous. Hence, no "cancel" action is required. } @Override public void store( Environment environment, Object result ){ // This type of node does not produce a result } }