diff options
author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2019-12-04 19:43:32 +0100 |
---|---|---|
committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2019-12-04 19:43:32 +0100 |
commit | 759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f (patch) | |
tree | 2132024fc058b1ef5338bf50df575a3244cc3f9f /eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process | |
parent | 4f15bdc45b08724d20c66c9fd74ea6a43a03c32f (diff) | |
download | EAAF-Components-759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f.tar.gz EAAF-Components-759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f.tar.bz2 EAAF-Components-759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f.zip |
common EGIZ code-style refactoring
Diffstat (limited to 'eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process')
20 files changed, 2120 insertions, 2226 deletions
diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExecutionContextImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExecutionContextImpl.java index 3cd696df..619911c1 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExecutionContextImpl.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExecutionContextImpl.java @@ -1,29 +1,22 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process; import java.io.Serializable; @@ -31,87 +24,88 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; - import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; /** * ExecutionContext implementation, related to a certain process instance. - * + * * @author tknall - * + * */ public class ExecutionContextImpl implements ExecutionContext { - private static final long serialVersionUID = 1L; - - private final Map<String, Serializable> ctxData = Collections.synchronizedMap(new HashMap<String, Serializable>()); - - private String processInstanceId; - private boolean markedAsCancelled = false; - - /** - * Creates a new instance. - */ - public ExecutionContextImpl() { - } - - /** - * Creates a new instance and associated it with a certain process instance. - */ - public ExecutionContextImpl(String processInstanceId) { - this.processInstanceId = processInstanceId; - } - - @Override - public void setProcessInstanceId(String processInstanceId) { - this.processInstanceId = processInstanceId; - } - - @Override - public String getProcessInstanceId() { - return processInstanceId; - } - - @Override - public Serializable get(String key) { - return ctxData.get(key); - } - - @Override - public Serializable remove(String key) { - return ctxData.remove(key); - } - - @Override - public void put(String key, Serializable object) { - ctxData.put(key, object); - } - - @Override - public Set<String> keySet() { - return Collections.unmodifiableSet(ctxData.keySet()); - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append("ExecutionContextImpl ["); - builder.append("id=").append(processInstanceId); - builder.append(", variables="); - builder.append(ctxData.keySet()); - builder.append("]"); - return builder.toString(); - } - - @Override - public boolean isProcessCancelled() { - return markedAsCancelled; - } - - @Override - public void setCanceleProcessFlag() { - markedAsCancelled = true; - - } + private static final long serialVersionUID = 1L; + + private final Map<String, Serializable> ctxData = + Collections.synchronizedMap(new HashMap<String, Serializable>()); + + private String processInstanceId; + private boolean markedAsCancelled = false; + + /** + * Creates a new instance. + */ + public ExecutionContextImpl() { + + } + + /** + * Creates a new instance and associated it with a certain process instance. + */ + public ExecutionContextImpl(final String processInstanceId) { + this.processInstanceId = processInstanceId; + } + + @Override + public void setProcessInstanceId(final String processInstanceId) { + this.processInstanceId = processInstanceId; + } + + @Override + public String getProcessInstanceId() { + return processInstanceId; + } + + @Override + public Serializable get(final String key) { + return ctxData.get(key); + } + + @Override + public Serializable remove(final String key) { + return ctxData.remove(key); + } + + @Override + public void put(final String key, final Serializable object) { + ctxData.put(key, object); + } + + @Override + public Set<String> keySet() { + return Collections.unmodifiableSet(ctxData.keySet()); + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("ExecutionContextImpl ["); + builder.append("id=").append(processInstanceId); + builder.append(", variables="); + builder.append(ctxData.keySet()); + builder.append("]"); + return builder.toString(); + } + + @Override + public boolean isProcessCancelled() { + return markedAsCancelled; + } + + @Override + public void setCanceleProcessFlag() { + markedAsCancelled = true; + + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExpressionEvaluationContextImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExpressionEvaluationContextImpl.java index 694b8d0d..72ad456f 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExpressionEvaluationContextImpl.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ExpressionEvaluationContextImpl.java @@ -1,29 +1,22 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process; import java.io.Serializable; @@ -31,40 +24,38 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; - import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext; /** * Context implementation used for expression evaluation only. - * + * * @author tknall - * + * */ public class ExpressionEvaluationContextImpl implements ExpressionEvaluationContext { - private static final long serialVersionUID = 1L; - - private Map<String, Serializable> ctxData; - - /** - * Creates a new instance and initializes it with data from a given process instance. - * - * @param processInstance - * The process instance. - */ - ExpressionEvaluationContextImpl(ProcessInstance processInstance) { - ExecutionContext executionContext = processInstance.getExecutionContext(); - Set<String> keys = executionContext.keySet(); - ctxData = Collections.synchronizedMap(new HashMap<String, Serializable>(keys.size())); - for (String key : keys) { - ctxData.put(key, executionContext.get(key)); - } - } - - @Override - public Map<String, Serializable> getCtx() { - return Collections.unmodifiableMap(ctxData); - } + private static final long serialVersionUID = 1L; + + private final Map<String, Serializable> ctxData; + + /** + * Creates a new instance and initializes it with data from a given process instance. + * + * @param processInstance The process instance. + */ + ExpressionEvaluationContextImpl(final ProcessInstance processInstance) { + final ExecutionContext executionContext = processInstance.getExecutionContext(); + final Set<String> keys = executionContext.keySet(); + ctxData = Collections.synchronizedMap(new HashMap<String, Serializable>(keys.size())); + for (final String key : keys) { + ctxData.put(key, executionContext.get(key)); + } + } + + @Override + public Map<String, Serializable> getCtx() { + return Collections.unmodifiableMap(ctxData); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java index f817f9fb..63ae66d5 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParser.java @@ -1,29 +1,22 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process; import java.io.IOException; @@ -32,7 +25,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Objects; - import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; @@ -48,203 +40,225 @@ import javax.xml.transform.stream.StreamSource; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import javax.xml.validation.Validator; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.xml.sax.SAXException; - import at.gv.egiz.eaaf.core.impl.idp.process.model.EndEvent; import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessDefinition; import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessNode; import at.gv.egiz.eaaf.core.impl.idp.process.model.StartEvent; import at.gv.egiz.eaaf.core.impl.idp.process.model.TaskInfo; import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; /** * Parses an XML representation of a process definition as defined by the respective XML schema. - * <p/ * The parser is thread-safe. + * * @author tknall * */ public class ProcessDefinitionParser { - - private static final String NS = "http://reference.e-government.gv.at/namespace/moa/process/definition/v1"; - - private static Logger log = LoggerFactory.getLogger(ProcessDefinitionParser.class); - - private static class LazyProcessDefinitionSchemaHolder { - private static final Schema PD_SCHEMA_INSTANCE; - static { - try (InputStream in = ProcessDefinitionParser.class.getResourceAsStream("/process/ProcessDefinition.xsd")) { - log.trace("Compiling process definition schema."); - SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); - // schema is thread-safe - PD_SCHEMA_INSTANCE = factory.newSchema(new StreamSource(in)); - } catch (Exception e) { - throw new RuntimeException("Unable to compile process definition schema.", e); - } - } - } - - /** - * Parses an XML representation of a process definition. The representation is being validated in order to suffice - * the related XML schema. - * - * @param processDefinitionInputStream - * The process definition. - * @return A new process definition. - * @throws ProcessDefinitionParserException - * Thrown in case of error parsing the process definition. - */ - public ProcessDefinition parse(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException { - XMLEventReader reader = null; - final ProcessDefinition pd = new ProcessDefinition(); - log.debug("Parsing and validating process definition."); - try { - - // Standard implementation of XMLInputFactory seems not to be thread-safe - XMLInputFactory inputFactory = XMLInputFactory.newInstance(); - reader = inputFactory.createXMLEventReader(processDefinitionInputStream); - - final List<StartElement> transitionElements = new ArrayList<>(); - final List<StartEvent> startEvents = new ArrayList<>(); - - reader = new EventReaderDelegate(reader) { - - @Override - public XMLEvent nextEvent() throws XMLStreamException { - XMLEvent event = super.nextEvent(); - - switch (event.getEventType()) { - case XMLStreamConstants.START_ELEMENT: - StartElement element = event.asStartElement(); - QName qname = element.getName(); - - if (NS.equals(qname.getNamespaceURI())) { - log.trace("Found process description element '{}'.", qname.getLocalPart()); - Attribute id = element.getAttributeByName(new QName("id")); - - switch (qname.getLocalPart()) { - case "ProcessDefinition": - if (id != null) { - pd.setId(id.getValue()); - } - break; - case "StartEvent": - StartEvent startEvent = new StartEvent(); - if (id != null) { - startEvent.setId(id.getValue()); - } - startEvents.add(startEvent); - break; - case "EndEvent": - EndEvent endEvent = new EndEvent(); - if (id != null) { - endEvent.setId(id.getValue()); - pd.getEndEvents().put(id.getValue(), endEvent); - } - break; - case "Transition": - transitionElements.add(element); - break; - case "Task": - TaskInfo taskInfo = new TaskInfo(); - if (id != null) { - taskInfo.setId(id.getValue()); - pd.getTaskInfos().put(id.getValue(), taskInfo); - } - Attribute async = element.getAttributeByName(new QName("async")); - if (async != null) { - taskInfo.setAsync(Boolean.valueOf(async.getValue())); - } - Attribute implementingClass = element.getAttributeByName(new QName("class")); - if (implementingClass != null) { - taskInfo.setTaskImplementingClass(implementingClass.getValue()); - } - break; - } - - } - - break; - } - - return event; - } - - }; - - // validator is not thread-safe - Validator validator = LazyProcessDefinitionSchemaHolder.PD_SCHEMA_INSTANCE.newValidator(); - validator.validate(new StAXSource(reader)); - log.trace("Process definition successfully schema validated."); - - // perform some basic checks - log.trace("Building model and performing some plausibility checks."); - if (startEvents.size() != 1) { - throw new ProcessDefinitionParserException("A ProcessDefinition must contain exactly one single StartEvent."); - } - pd.setStartEvent(startEvents.get(0)); - - // link transitions - Iterator<StartElement> transitions = transitionElements.iterator(); - while (transitions.hasNext()) { - StartElement element = transitions.next(); - Transition transition = new Transition(); - Attribute id = element.getAttributeByName(new QName("id")); - if (id != null) { - transition.setId(id.getValue()); - } - Attribute conditionExpression = element.getAttributeByName(new QName("conditionExpression")); - if (conditionExpression != null) { - transition.setConditionExpression(conditionExpression.getValue()); - } - Attribute from = element.getAttributeByName(new QName("from")); - if (from != null) { - ProcessNode fromNode = pd.getProcessNode(from.getValue()); - if (fromNode == null) { - throw new ProcessDefinitionParserException("Transition's 'from'-attribute refers to a non-existing event or task '" + from.getValue() + '.'); - } - if (fromNode instanceof EndEvent) { - throw new ProcessDefinitionParserException("Transition cannot start from end event."); - } - transition.setFrom(fromNode); - fromNode.getOutgoingTransitions().add(transition); - } - Attribute to = element.getAttributeByName(new QName("to")); - if (to != null) { - ProcessNode toNode = pd.getProcessNode(to.getValue()); - if (toNode == null) { - throw new ProcessDefinitionParserException("Transition's 'to'-attribute refers to a non-existing event or task '" + to.getValue() + '.'); - } - transition.setTo(toNode); - toNode.getIncomingTransitions().add(transition); - } - if (transition.getConditionExpression() == null && Objects.equals(transition.getFrom(), transition.getTo())) { - throw new ProcessDefinitionParserException("Transition's 'from' equals its 'to'. Since no 'conditionExpression' has been set this will cause a loop."); - } - } - log.debug("Process definition '{}' successfully parsed.", pd.getId()); - return pd; - - } catch (ProcessDefinitionParserException e) { - throw e; - } catch (XMLStreamException|IOException e) { - throw new ProcessDefinitionParserException("Unable to read process definition from inputstream.", e); - } catch (SAXException e) { - throw new ProcessDefinitionParserException("Schema validation of process description failed.", e); - } catch (Exception e) { - throw new ProcessDefinitionParserException("Internal error creating process definition from inputstream.", e); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (XMLStreamException e) { - // error freeing resources - } - } - } - } + + private static final String NS = + "http://reference.e-government.gv.at/namespace/moa/process/definition/v1"; + + private static Logger log = LoggerFactory.getLogger(ProcessDefinitionParser.class); + + private static class LazyProcessDefinitionSchemaHolder { + private static final Schema PD_SCHEMA_INSTANCE; + + static { + try (InputStream in = + ProcessDefinitionParser.class.getResourceAsStream("/process/ProcessDefinition.xsd")) { + log.trace("Compiling process definition schema."); + final SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); + // schema is thread-safe + PD_SCHEMA_INSTANCE = factory.newSchema(new StreamSource(in)); + } catch (final Exception e) { + throw new RuntimeException("Unable to compile process definition schema.", e); + } + } + } + + /** + * Parses an XML representation of a process definition. The representation is being validated in + * order to suffice the related XML schema. + * + * @param processDefinitionInputStream The process definition. + * @return A new process definition. + * @throws ProcessDefinitionParserException Thrown in case of error parsing the process + * definition. + */ + public ProcessDefinition parse(final InputStream processDefinitionInputStream) + throws ProcessDefinitionParserException { + XMLEventReader reader = null; + final ProcessDefinition pd = new ProcessDefinition(); + log.debug("Parsing and validating process definition."); + try { + + // Standard implementation of XMLInputFactory seems not to be thread-safe + final XMLInputFactory inputFactory = XMLInputFactory.newInstance(); + reader = inputFactory.createXMLEventReader(processDefinitionInputStream); + + final List<StartElement> transitionElements = new ArrayList<>(); + final List<StartEvent> startEvents = new ArrayList<>(); + + reader = new EventReaderDelegate(reader) { + + @Override + public XMLEvent nextEvent() throws XMLStreamException { + final XMLEvent event = super.nextEvent(); + + switch (event.getEventType()) { + case XMLStreamConstants.START_ELEMENT: + final StartElement element = event.asStartElement(); + final QName qname = element.getName(); + + if (NS.equals(qname.getNamespaceURI())) { + log.trace("Found process description element '{}'.", qname.getLocalPart()); + final Attribute id = element.getAttributeByName(new QName("id")); + + switch (qname.getLocalPart()) { + case "ProcessDefinition": + if (id != null) { + pd.setId(id.getValue()); + } + break; + case "StartEvent": + final StartEvent startEvent = new StartEvent(); + if (id != null) { + startEvent.setId(id.getValue()); + } + startEvents.add(startEvent); + break; + case "EndEvent": + final EndEvent endEvent = new EndEvent(); + if (id != null) { + endEvent.setId(id.getValue()); + pd.getEndEvents().put(id.getValue(), endEvent); + } + break; + case "Transition": + transitionElements.add(element); + break; + case "Task": + final TaskInfo taskInfo = new TaskInfo(); + if (id != null) { + taskInfo.setId(id.getValue()); + pd.getTaskInfos().put(id.getValue(), taskInfo); + } + final Attribute async = element.getAttributeByName(new QName("async")); + if (async != null) { + taskInfo.setAsync(Boolean.valueOf(async.getValue())); + } + final Attribute implementingClass = + element.getAttributeByName(new QName("class")); + if (implementingClass != null) { + taskInfo.setTaskImplementingClass(implementingClass.getValue()); + } + break; + default: + log.warn("Ignore unknown event: {}", qname); + break; + } + + } + + break; + default: + log.warn("Ignore unknown event: {}", event); + break; + } + + return event; + } + + }; + + // validator is not thread-safe + final Validator validator = + LazyProcessDefinitionSchemaHolder.PD_SCHEMA_INSTANCE.newValidator(); + validator.validate(new StAXSource(reader)); + log.trace("Process definition successfully schema validated."); + + // perform some basic checks + log.trace("Building model and performing some plausibility checks."); + if (startEvents.size() != 1) { + throw new ProcessDefinitionParserException( + "A ProcessDefinition must contain exactly one single StartEvent."); + } + pd.setStartEvent(startEvents.get(0)); + + // link transitions + final Iterator<StartElement> transitions = transitionElements.iterator(); + while (transitions.hasNext()) { + final StartElement element = transitions.next(); + final Transition transition = new Transition(); + final Attribute id = element.getAttributeByName(new QName("id")); + if (id != null) { + transition.setId(id.getValue()); + } + final Attribute conditionExpression = + element.getAttributeByName(new QName("conditionExpression")); + if (conditionExpression != null) { + transition.setConditionExpression(conditionExpression.getValue()); + } + final Attribute from = element.getAttributeByName(new QName("from")); + if (from != null) { + final ProcessNode fromNode = pd.getProcessNode(from.getValue()); + if (fromNode == null) { + throw new ProcessDefinitionParserException( + "Transition's 'from'-attribute refers to a non-existing event or task '" + + from.getValue() + '.'); + } + if (fromNode instanceof EndEvent) { + throw new ProcessDefinitionParserException("Transition cannot start from end event."); + } + transition.setFrom(fromNode); + fromNode.getOutgoingTransitions().add(transition); + } + final Attribute to = element.getAttributeByName(new QName("to")); + if (to != null) { + final ProcessNode toNode = pd.getProcessNode(to.getValue()); + if (toNode == null) { + throw new ProcessDefinitionParserException( + "Transition's 'to'-attribute refers to a non-existing event or task '" + + to.getValue() + '.'); + } + transition.setTo(toNode); + toNode.getIncomingTransitions().add(transition); + } + if (transition.getConditionExpression() == null + && Objects.equals(transition.getFrom(), transition.getTo())) { + throw new ProcessDefinitionParserException( + "Transition's 'from' equals its 'to'. Since no 'conditionExpression' " + + "has been set this will cause a loop."); + } + } + log.debug("Process definition '{}' successfully parsed.", pd.getId()); + return pd; + + } catch (final ProcessDefinitionParserException e) { + throw e; + } catch (XMLStreamException | IOException e) { + throw new ProcessDefinitionParserException( + "Unable to read process definition from inputstream.", e); + } catch (final SAXException e) { + throw new ProcessDefinitionParserException("Schema validation of process description failed.", + e); + } catch (final Exception e) { + throw new ProcessDefinitionParserException( + "Internal error creating process definition from inputstream.", e); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (final XMLStreamException e) { + e.printStackTrace(); + + } + } + } + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParserException.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParserException.java index 292b3881..472d6469 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParserException.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessDefinitionParserException.java @@ -1,61 +1,52 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process; /** * Exception thrown in case of error parsing a process definition. - * + * * @author tknall - * + * */ public class ProcessDefinitionParserException extends Exception { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - /** - * Creates a new parser exception providing a {@code message} describing the reason and the {@code cause}. - * - * @param message - * The message. - * @param cause - * The cause. - */ - public ProcessDefinitionParserException(String message, Throwable cause) { - super(message, cause); - } + /** + * Creates a new parser exception providing a {@code message} describing the reason and the + * {@code cause}. + * + * @param message The message. + * @param cause The cause. + */ + public ProcessDefinitionParserException(final String message, final Throwable cause) { + super(message, cause); + } - /** - * Creates a new parser exception providing a {@code message} describing the reason. - * - * @param message - * The message. - */ - public ProcessDefinitionParserException(String message) { - super(message); - } + /** + * Creates a new parser exception providing a {@code message} describing the reason. + * + * @param message The message. + */ + public ProcessDefinitionParserException(final String message) { + super(message); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java index 53f50e1f..0c4946af 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessEngineImpl.java @@ -1,55 +1,39 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process; import java.io.InputStream; import java.io.Serializable; import java.util.HashMap; import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.collections4.IterableUtils; -import org.apache.commons.collections4.Predicate; -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; - import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.data.EAAFConstants; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext; import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluator; import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine; -import at.gv.egiz.eaaf.core.api.idp.process.ProcessInstanceStoreDAO; +import at.gv.egiz.eaaf.core.api.idp.process.ProcessInstanceStoreDao; import at.gv.egiz.eaaf.core.api.idp.process.Task; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; +import at.gv.egiz.eaaf.core.exceptions.EaafException; import at.gv.egiz.eaaf.core.exceptions.ProcessExecutionException; import at.gv.egiz.eaaf.core.impl.idp.process.dao.ProcessInstanceStore; import at.gv.egiz.eaaf.core.impl.idp.process.model.EndEvent; @@ -58,439 +42,491 @@ import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessNode; import at.gv.egiz.eaaf.core.impl.idp.process.model.StartEvent; import at.gv.egiz.eaaf.core.impl.idp.process.model.TaskInfo; import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition; +import org.apache.commons.collections4.IterableUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; /** - * Process engine implementation allowing starting and continuing processes as well as providing means for cleanup actions. + * Process engine implementation allowing starting and continuing processes as well as providing + * means for cleanup actions. */ public class ProcessEngineImpl implements ProcessEngine { - - private final Logger log = LoggerFactory.getLogger(getClass()); - - @Autowired ProcessInstanceStoreDAO piStoreDao; - @Autowired ApplicationContext context; - - private final ProcessDefinitionParser pdp = new ProcessDefinitionParser(); - - private final Map<String, ProcessDefinition> processDefinitions = new ConcurrentHashMap<String, ProcessDefinition>(); - - private final static String MDC_CTX_PI_NAME = "processInstanceId"; - private final static String MDC_CTX_TASK_NAME = "taskId"; - - private ExpressionEvaluator transitionConditionExpressionEvaluator; - - @Override - public void registerProcessDefinition(ProcessDefinition processDefinition) { - log.info("Registering process definition '{}'.", processDefinition.getId()); - processDefinitions.put(processDefinition.getId(), processDefinition); - } - - @Override - public String registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException{ - final ProcessDefinition pd = pdp.parse(processDefinitionInputStream); - - postValidationOfProcessDefintion(pd); - - registerProcessDefinition(pd); - return pd.getId(); - } - - /** - * Sets the process definitions. - * - * @param processDefinitions - * The process definitions. - * @throws IllegalArgumentException - * In case the process definitions contain definitions with the same identifier. - */ - public void setProcessDefinitions(Iterable<ProcessDefinition> processDefinitions) { - this.processDefinitions.clear(); - for (final ProcessDefinition pd : processDefinitions) { - if (this.processDefinitions.containsKey(pd.getId())) { - throw new IllegalArgumentException("Duplicate process definition identifier '" + pd.getId() + "'."); - } - registerProcessDefinition(pd); - } - } - - /** - * Sets an expression evaluator that should be used to process transition condition expressions. - * @param transitionConditionExpressionEvaluator The expression evaluator. - */ - public void setTransitionConditionExpressionEvaluator( - ExpressionEvaluator transitionConditionExpressionEvaluator) { - this.transitionConditionExpressionEvaluator = transitionConditionExpressionEvaluator; - } - - - @Override - public String createProcessInstance(String processDefinitionId, ExecutionContext executionContext) throws ProcessExecutionException { - // look for respective process definition - final ProcessDefinition pd = processDefinitions.get(processDefinitionId); - if (pd == null) { - throw new ProcessExecutionException("Unable to find process definition for process '" + processDefinitionId + "'."); - } - // create and keep process instance - final ProcessInstance pi = new ProcessInstance(pd, executionContext); - log.info("Creating process instance from process definition '{}': {}", processDefinitionId, pi.getId()); - - try { - saveOrUpdateProcessInstance(pi); - - } catch (final EAAFException e) { - throw new ProcessExecutionException("Unable to persist process instance.", e); - } - - return pi.getId(); - } - - @Override - public String createProcessInstance(String processDefinitionId) throws ProcessExecutionException { - return createProcessInstance(processDefinitionId, null); - } - - @Override - public void start(IRequest pendingReq) throws ProcessExecutionException { - try { - if (StringUtils.isEmpty(pendingReq.getProcessInstanceId())) { - log.error("Pending-request with id:" + pendingReq.getPendingRequestId() - + " includes NO 'ProcessInstanceId'"); - throw new ProcessExecutionException("Pending-request with id:" + pendingReq.getPendingRequestId() - + " includes NO 'ProcessInstanceId'"); - } - - final ProcessInstance pi = loadProcessInstance(pendingReq.getProcessInstanceId()); - - if (pi == null ) { - throw new ProcessExecutionException("Process instance '" + pendingReq.getProcessInstanceId() + "' does not exist."); - - } - - MDC.put(MDC_CTX_PI_NAME, pi.getId()); - - if (!ProcessInstanceState.NOT_STARTED.equals(pi.getState())) { - throw new ProcessExecutionException("Process instance '" + pi.getId() + "' has already been started (current state is " + pi.getState() + ")."); - } - log.info("Starting process instance '{}'.", pi.getId()); - // execute process - pi.setState(ProcessInstanceState.STARTED); - execute(pi, pendingReq); - - //store ProcessInstance if it is not already ended - if (!ProcessInstanceState.ENDED.equals(pi.getState())) - saveOrUpdateProcessInstance(pi); - - } catch (final EAAFException e) { - throw new ProcessExecutionException("Unable to load/save process instance.", e); - - } finally { - MDC.remove(MDC_CTX_PI_NAME); - } - } - - @Override - public void signal(IRequest pendingReq) throws ProcessExecutionException { - - try { - if (StringUtils.isEmpty(pendingReq.getProcessInstanceId())) { - log.error("Pending-request with id:" + pendingReq.getPendingRequestId() - + " includes NO 'ProcessInstanceId'"); - throw new ProcessExecutionException("Pending-request with id:" + pendingReq.getPendingRequestId() - + " includes NO 'ProcessInstanceId'"); - } - - final ProcessInstance pi = loadProcessInstance(pendingReq.getProcessInstanceId()); - - if (pi == null ) { - throw new ProcessExecutionException("Process instance '" + pendingReq.getProcessInstanceId() + "' does not exist."); - - } - - MDC.put(MDC_CTX_PI_NAME, pi.getId()); - - if (!ProcessInstanceState.SUSPENDED.equals(pi.getState())) { - throw new ProcessExecutionException("Process instance '" + pi.getId() + "' has not been suspended (current state is " + pi.getState() + ")."); - } - - log.debug("Waking up process instance '{}'.", pi.getId()); - pi.setState(ProcessInstanceState.STARTED); - - //put pending-request ID on execution-context because it could be changed - pi.getExecutionContext().put(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, pendingReq.getPendingRequestId()); - - execute(pi, pendingReq); - - //store ProcessInstance if it is not already ended - if (!ProcessInstanceState.ENDED.equals(pi.getState())) - saveOrUpdateProcessInstance(pi); - - } catch (final EAAFException e) { - throw new ProcessExecutionException("Unable to load/save process instance.", e); - - } finally { - MDC.remove(MDC_CTX_PI_NAME); - } - } - - - /** - * Instantiates a task implementation given by a {@link TaskInfo}. - * @param ti The task info. - * @return A Task implementation or {@code null} if the task info does not reference any task implementing classes. - * @throws ProcessExecutionException Thrown in case of error (when the referenced class does not implement {@link Task} for instance). - */ - private Task createTaskInstance(TaskInfo ti) throws ProcessExecutionException { - final String clazz = StringUtils.trimToNull(ti.getTaskImplementingClass()); - Task task = null; - - if (clazz != null) { - log.debug("Instantiating task implementing class '{}'.", clazz); - Object instanceClass = null; - try { - instanceClass = context.getBean(clazz); - - } catch (final Exception e) { - throw new ProcessExecutionException("Unable to get class '" + clazz + "' associated with task '" + ti.getId() + "' .", e); - - } - if (instanceClass == null || !(instanceClass instanceof Task)) { - throw new ProcessExecutionException("Class '" + clazz + "' associated with task '" + ti.getId() + "' is not assignable to " + Task.class.getName() + "."); - - } - try { - task = (Task) instanceClass; - - } catch (final Exception e) { - throw new ProcessExecutionException("Unable to instantiate class '" + clazz + "' associated with task '" + ti.getId() + "' .", e); - } - } - - return task; - } - - /** - * Starts/executes a given process instance. - * @param pi The process instance. - * @param pendingReq - * @throws ProcessExecutionException Thrown in case of error. - */ - private void execute(final ProcessInstance pi, IRequest pendingReq) throws ProcessExecutionException { - if (ProcessInstanceState.ENDED.equals(pi.getState())) { - throw new ProcessExecutionException("Process for instance '" + pi.getId() + "' has already been ended."); - } - final ProcessDefinition pd = pi.getProcessDefinition(); - final ProcessNode processNode = pd.getProcessNode(pi.getNextId()); - log.debug("Processing node '{}'.", processNode.getId()); - - // distinguish process node types StartEvent, TaskInfo and EndEvent - - if (processNode instanceof TaskInfo) { - // TaskInfo types need to be executed - final TaskInfo ti = (TaskInfo) processNode; - MDC.put(MDC_CTX_TASK_NAME, ti.getId()); - try { - log.debug("Processing task '{}'.", ti.getId()); - final Task task = createTaskInstance(ti); - if (task != null) { - try { - log.debug("Executing task implementation for task '{}'.", ti.getId()); - log.trace("Execution context before task execution: {}", pi.getExecutionContext().keySet()); - pendingReq = task.execute(pendingReq, pi.getExecutionContext()); - log.debug("Returned from execution of task '{}'.", ti.getId()); - log.trace("Execution context after task execution: {}", pi.getExecutionContext().keySet()); - - } catch (final Throwable t) { - throw new ProcessExecutionException("Error executing task '" + ti.getId() + "'.", t); - - } - - //check if process was cancelled dynamically by task - if (pi.getExecutionContext().isProcessCancelled()) { - log.debug("Processing task '{}' was cancelled by Task: '{}'.", pi.getId(), ti.getId()); - processFinishEvent(pi); - return; - - } - - } else { - log.debug("No task implementing class set."); - - } - } finally { - MDC.remove(MDC_CTX_TASK_NAME); - - } - - } else if (processNode instanceof EndEvent) { - processFinishEvent(pi); - return; - - } - - final ExpressionEvaluationContext expressionContext = new ExpressionEvaluationContextImpl(pi); - - // traverse pointer - final Transition t = IterableUtils.find(processNode.getOutgoingTransitions(), new Predicate<Transition>() { - @Override - public boolean evaluate(Transition transition) { - if (transitionConditionExpressionEvaluator != null && transition.getConditionExpression() != null) { - log.trace("Evaluating transition expression '{}'.", transition.getConditionExpression()); - return transitionConditionExpressionEvaluator.evaluate(expressionContext, transition.getConditionExpression()); - } - return true; - } - }); - if (t == null) { - throw new ProcessExecutionException("No valid transition starting from process node '" + processNode.getId()+ "'."); - } - log.trace("Found suitable transition: {}", t); - // update pointer - log.trace("Shifting process token from '{}' to '{}'.", pi.getNextId(), t.getTo().getId()); - pi.setNextId(t.getTo().getId()); - - // inspect current task - if (t.getTo() instanceof TaskInfo && (((TaskInfo) t.getTo()).isAsync())) { - // immediately return in case of asynchonous task - log.debug("Suspending process instance '{}' for asynchronous task '{}'.", pi.getId(), t.getTo().getId()); - pi.setState(ProcessInstanceState.SUSPENDED); - return; - } - - // continue execution in case of StartEvent or Task - if (processNode instanceof StartEvent || processNode instanceof TaskInfo) { - execute(pi, pendingReq); - } - } - - @Override - public ProcessInstance getProcessInstance(String processInstanceId) { - - ProcessInstance processInstance; - try { - processInstance = loadProcessInstance(processInstanceId); - - } catch (final EAAFException e) { - throw new RuntimeException("The process instance '" + processInstanceId + "' could not be retrieved.", e); - } - - if (processInstance == null) { - throw new IllegalArgumentException("The process instance '" + processInstanceId + "' does not/no longer exist."); - } - - return processInstance; - } - - /** - * Persists a {@link ProcessInstance} to the database. - * @param processInstance The object to persist. - * @throws MOADatabaseException Thrown if an error occurs while accessing the database. - */ - private void saveOrUpdateProcessInstance(ProcessInstance processInstance) throws EAAFException { - final ProcessInstanceStore store = new ProcessInstanceStore(); - - final ExecutionContext ctx = processInstance.getExecutionContext(); - - final Map<String, Serializable> ctxData = new HashMap<String, Serializable>(); - for (final String key : ctx.keySet()) { - ctxData.put(key, ctx.get(key)); - } - store.setExecutionContextData(ctxData); - - store.setNextTaskId(processInstance.getNextId()); - store.setProcessDefinitionId(processInstance.getProcessDefinition().getId()); - - store.setProcessInstanceId(processInstance.getId()); - store.setProcessState(processInstance.getState()); - - piStoreDao.saveOrUpdate(store); - } - - /** - * Load a {@link ProcessInstance} with a certain id from the database. - * @param processInstanceId The process instance id - * @return The process instance corresponding to the id or {@code null} if no such object is found. - * @throws MOADatabaseException Thrown if an error occurs while accessing the database. - */ - private ProcessInstance loadProcessInstance(String processInstanceId) throws EAAFException { - - final ProcessInstanceStore piStore = piStoreDao.load(processInstanceId); - - if (piStore == null) { - return null; - } - - final ExecutionContext executionContext = new ExecutionContextImpl(piStore.getProcessInstanceId()); - - final Map<String, Serializable> executionContextData = piStore.getExecutionContextData(); - for (final String key : executionContextData.keySet()) { - executionContext.put(key, executionContextData.get(key)); - } - - final ProcessInstance pi = new ProcessInstance(processDefinitions.get(piStore.getProcessDefinitionId()), executionContext); - pi.setNextId(piStore.getNextTaskId()); - pi.setState(piStore.getProcessState()); - - return pi; - } - - /* (non-Javadoc) - * @see at.gv.egovernment.moa.id.process.ProcessEngine#deleteProcessInstance(java.lang.String) - */ - @Override - public void deleteProcessInstance(String processInstanceId) throws ProcessExecutionException { - if (StringUtils.isEmpty(processInstanceId)) { - throw new ProcessExecutionException("Unable to remove process instance: ProcessInstanceId is empty"); - - } - - try { - piStoreDao.remove(processInstanceId); - - } catch (final EAAFException e) { - throw new ProcessExecutionException("Unable to remove process instance.", e); - - } - - } - - /** - * Finish a process-flow and remove any process-flow related information - * - * @param pi - * @throws ProcessExecutionException - */ - private void processFinishEvent(ProcessInstance pi) throws ProcessExecutionException { - log.info("Finishing process instance '{}'.", pi.getId()); - - try { - piStoreDao.remove(pi.getId()); - - } catch (final EAAFException e) { - throw new ProcessExecutionException("Unable to remove process instance.", e); - - } - pi.setState(ProcessInstanceState.ENDED); - log.debug("Final process context: {}", pi.getExecutionContext().keySet()); - - } - - /** - * Perform some post-validation operations on process definition - * - * Like: check if all tasks that are defined are available on context - * - * @param pd - * @throws ProcessDefinitionParserException - */ - private void postValidationOfProcessDefintion(ProcessDefinition pd) throws ProcessDefinitionParserException{ - try { - for(final TaskInfo task : pd.getTaskInfos().values()) { - createTaskInstance(task); - } - - } catch (final ProcessExecutionException e) { - log.error("Post-validation of process definition: {} find an error: {}", pd.getId(), e.getMessage()); - throw new ProcessDefinitionParserException("Post-validation find an error in process definition:" + pd.getId(), e); - - } - } + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Autowired + ProcessInstanceStoreDao piStoreDao; + @Autowired + ApplicationContext context; + + private final ProcessDefinitionParser pdp = new ProcessDefinitionParser(); + + private final Map<String, ProcessDefinition> processDefinitions = new ConcurrentHashMap<>(); + + private static final String MDC_CTX_PI_NAME = "processInstanceId"; + private static final String MDC_CTX_TASK_NAME = "taskId"; + + private ExpressionEvaluator transitionConditionExpressionEvaluator; + + @Override + public void registerProcessDefinition(final ProcessDefinition processDefinition) { + log.info("Registering process definition '{}'.", processDefinition.getId()); + processDefinitions.put(processDefinition.getId(), processDefinition); + } + + @Override + public String registerProcessDefinition(final InputStream processDefinitionInputStream) + throws ProcessDefinitionParserException { + final ProcessDefinition pd = pdp.parse(processDefinitionInputStream); + + postValidationOfProcessDefintion(pd); + + registerProcessDefinition(pd); + return pd.getId(); + } + + /** + * Sets the process definitions. + * + * @param processDefinitions The process definitions. + * @throws IllegalArgumentException In case the process definitions contain definitions with the + * same identifier. + */ + public void setProcessDefinitions(final Iterable<ProcessDefinition> processDefinitions) { + this.processDefinitions.clear(); + for (final ProcessDefinition pd : processDefinitions) { + if (this.processDefinitions.containsKey(pd.getId())) { + throw new IllegalArgumentException( + "Duplicate process definition identifier '" + pd.getId() + "'."); + } + registerProcessDefinition(pd); + } + } + + /** + * Sets an expression evaluator that should be used to process transition condition expressions. + * + * @param transitionConditionExpressionEvaluator The expression evaluator. + */ + public void setTransitionConditionExpressionEvaluator( + final ExpressionEvaluator transitionConditionExpressionEvaluator) { + this.transitionConditionExpressionEvaluator = transitionConditionExpressionEvaluator; + } + + + @Override + public String createProcessInstance(final String processDefinitionId, + final ExecutionContext executionContext) throws ProcessExecutionException { + // look for respective process definition + final ProcessDefinition pd = processDefinitions.get(processDefinitionId); + if (pd == null) { + throw new ProcessExecutionException( + "Unable to find process definition for process '" + processDefinitionId + "'."); + } + // create and keep process instance + final ProcessInstance pi = new ProcessInstance(pd, executionContext); + log.info("Creating process instance from process definition '{}': {}", processDefinitionId, + pi.getId()); + + try { + saveOrUpdateProcessInstance(pi); + + } catch (final EaafException e) { + throw new ProcessExecutionException("Unable to persist process instance.", e); + } + + return pi.getId(); + } + + @Override + public String createProcessInstance(final String processDefinitionId) + throws ProcessExecutionException { + return createProcessInstance(processDefinitionId, null); + } + + @Override + public void start(final IRequest pendingReq) throws ProcessExecutionException { + try { + if (StringUtils.isEmpty(pendingReq.getProcessInstanceId())) { + log.error("Pending-request with id:" + pendingReq.getPendingRequestId() + + " includes NO 'ProcessInstanceId'"); + throw new ProcessExecutionException("Pending-request with id:" + + pendingReq.getPendingRequestId() + " includes NO 'ProcessInstanceId'"); + } + + final ProcessInstance pi = loadProcessInstance(pendingReq.getProcessInstanceId()); + + if (pi == null) { + throw new ProcessExecutionException( + "Process instance '" + pendingReq.getProcessInstanceId() + "' does not exist."); + + } + + MDC.put(MDC_CTX_PI_NAME, pi.getId()); + + if (!ProcessInstanceState.NOT_STARTED.equals(pi.getState())) { + throw new ProcessExecutionException("Process instance '" + pi.getId() + + "' has already been started (current state is " + pi.getState() + ")."); + } + log.info("Starting process instance '{}'.", pi.getId()); + // execute process + pi.setState(ProcessInstanceState.STARTED); + execute(pi, pendingReq); + + // store ProcessInstance if it is not already ended + if (!ProcessInstanceState.ENDED.equals(pi.getState())) { + saveOrUpdateProcessInstance(pi); + } + + } catch (final EaafException e) { + throw new ProcessExecutionException("Unable to load/save process instance.", e); + + } finally { + MDC.remove(MDC_CTX_PI_NAME); + } + } + + @Override + public void signal(final IRequest pendingReq) throws ProcessExecutionException { + + try { + if (StringUtils.isEmpty(pendingReq.getProcessInstanceId())) { + log.error("Pending-request with id:" + pendingReq.getPendingRequestId() + + " includes NO 'ProcessInstanceId'"); + throw new ProcessExecutionException("Pending-request with id:" + + pendingReq.getPendingRequestId() + " includes NO 'ProcessInstanceId'"); + } + + final ProcessInstance pi = loadProcessInstance(pendingReq.getProcessInstanceId()); + + if (pi == null) { + throw new ProcessExecutionException( + "Process instance '" + pendingReq.getProcessInstanceId() + "' does not exist."); + + } + + MDC.put(MDC_CTX_PI_NAME, pi.getId()); + + if (!ProcessInstanceState.SUSPENDED.equals(pi.getState())) { + throw new ProcessExecutionException("Process instance '" + pi.getId() + + "' has not been suspended (current state is " + pi.getState() + ")."); + } + + log.debug("Waking up process instance '{}'.", pi.getId()); + pi.setState(ProcessInstanceState.STARTED); + + // put pending-request ID on execution-context because it could be changed + pi.getExecutionContext().put(EAAFConstants.PARAM_HTTP_TARGET_PENDINGREQUESTID, + pendingReq.getPendingRequestId()); + + execute(pi, pendingReq); + + // store ProcessInstance if it is not already ended + if (!ProcessInstanceState.ENDED.equals(pi.getState())) { + saveOrUpdateProcessInstance(pi); + } + + } catch (final EaafException e) { + throw new ProcessExecutionException("Unable to load/save process instance.", e); + + } finally { + MDC.remove(MDC_CTX_PI_NAME); + } + } + + + /** + * Instantiates a task implementation given by a {@link TaskInfo}. + * + * @param ti The task info. + * @return A Task implementation or {@code null} if the task info does not reference any task + * implementing classes. + * @throws ProcessExecutionException Thrown in case of error (when the referenced class does not + * implement {@link Task} for instance). + */ + private Task createTaskInstance(final TaskInfo ti) throws ProcessExecutionException { + final String clazz = StringUtils.trimToNull(ti.getTaskImplementingClass()); + Task task = null; + + if (clazz != null) { + log.debug("Instantiating task implementing class '{}'.", clazz); + Object instanceClass = null; + try { + instanceClass = context.getBean(clazz); + + } catch (final Exception e) { + throw new ProcessExecutionException( + "Unable to get class '" + clazz + "' associated with task '" + ti.getId() + "' .", e); + + } + if (instanceClass == null || !(instanceClass instanceof Task)) { + throw new ProcessExecutionException("Class '" + clazz + "' associated with task '" + + ti.getId() + "' is not assignable to " + Task.class.getName() + "."); + + } + try { + task = (Task) instanceClass; + + } catch (final Exception e) { + throw new ProcessExecutionException("Unable to instantiate class '" + clazz + + "' associated with task '" + ti.getId() + "' .", e); + } + } + + return task; + } + + /** + * Starts/executes a given process instance. + * + * @param pi The process instance. + * @param pendingReq current pending request + * @throws ProcessExecutionException Thrown in case of error. + */ + private void execute(final ProcessInstance pi, IRequest pendingReq) + throws ProcessExecutionException { + if (ProcessInstanceState.ENDED.equals(pi.getState())) { + throw new ProcessExecutionException( + "Process for instance '" + pi.getId() + "' has already been ended."); + } + final ProcessDefinition pd = pi.getProcessDefinition(); + final ProcessNode processNode = pd.getProcessNode(pi.getNextId()); + log.debug("Processing node '{}'.", processNode.getId()); + + // distinguish process node types StartEvent, TaskInfo and EndEvent + + if (processNode instanceof TaskInfo) { + // TaskInfo types need to be executed + final TaskInfo ti = (TaskInfo) processNode; + MDC.put(MDC_CTX_TASK_NAME, ti.getId()); + try { + log.debug("Processing task '{}'.", ti.getId()); + final Task task = createTaskInstance(ti); + if (task != null) { + try { + log.debug("Executing task implementation for task '{}'.", ti.getId()); + log.trace("Execution context before task execution: {}", + pi.getExecutionContext().keySet()); + pendingReq = task.execute(pendingReq, pi.getExecutionContext()); + log.debug("Returned from execution of task '{}'.", ti.getId()); + log.trace("Execution context after task execution: {}", + pi.getExecutionContext().keySet()); + + } catch (final Throwable t) { + throw new ProcessExecutionException("Error executing task '" + ti.getId() + "'.", t); + + } + + // check if process was cancelled dynamically by task + if (pi.getExecutionContext().isProcessCancelled()) { + log.debug("Processing task '{}' was cancelled by Task: '{}'.", pi.getId(), ti.getId()); + processFinishEvent(pi); + return; + + } + + } else { + log.debug("No task implementing class set."); + + } + } finally { + MDC.remove(MDC_CTX_TASK_NAME); + + } + + } else if (processNode instanceof EndEvent) { + processFinishEvent(pi); + return; + + } + + final ExpressionEvaluationContext expressionContext = new ExpressionEvaluationContextImpl(pi); + + // traverse pointer + final Transition t = IterableUtils.find(processNode.getOutgoingTransitions(), transition -> { + if (transitionConditionExpressionEvaluator != null + && transition.getConditionExpression() != null) { + log.trace("Evaluating transition expression '{}'.", transition.getConditionExpression()); + return transitionConditionExpressionEvaluator.evaluate(expressionContext, + transition.getConditionExpression()); + } + return true; + }); + if (t == null) { + throw new ProcessExecutionException( + "No valid transition starting from process node '" + processNode.getId() + "'."); + } + log.trace("Found suitable transition: {}", t); + // update pointer + log.trace("Shifting process token from '{}' to '{}'.", pi.getNextId(), t.getTo().getId()); + pi.setNextId(t.getTo().getId()); + + // inspect current task + if (t.getTo() instanceof TaskInfo && (((TaskInfo) t.getTo()).isAsync())) { + // immediately return in case of asynchonous task + log.debug("Suspending process instance '{}' for asynchronous task '{}'.", pi.getId(), + t.getTo().getId()); + pi.setState(ProcessInstanceState.SUSPENDED); + return; + } + + // continue execution in case of StartEvent or Task + if (processNode instanceof StartEvent || processNode instanceof TaskInfo) { + execute(pi, pendingReq); + } + } + + @Override + public ProcessInstance getProcessInstance(final String processInstanceId) { + + ProcessInstance processInstance; + try { + processInstance = loadProcessInstance(processInstanceId); + + } catch (final EaafException e) { + throw new RuntimeException( + "The process instance '" + processInstanceId + "' could not be retrieved.", e); + } + + if (processInstance == null) { + throw new IllegalArgumentException( + "The process instance '" + processInstanceId + "' does not/no longer exist."); + } + + return processInstance; + } + + /** + * Persists a {@link ProcessInstance} to the database. + * + * @param processInstance The object to persist. + * @throws MOADatabaseException Thrown if an error occurs while accessing the database. + */ + private void saveOrUpdateProcessInstance(final ProcessInstance processInstance) + throws EaafException { + final ProcessInstanceStore store = new ProcessInstanceStore(); + + final ExecutionContext ctx = processInstance.getExecutionContext(); + + final Map<String, Serializable> ctxData = new HashMap<>(); + for (final String key : ctx.keySet()) { + ctxData.put(key, ctx.get(key)); + } + store.setExecutionContextData(ctxData); + + store.setNextTaskId(processInstance.getNextId()); + store.setProcessDefinitionId(processInstance.getProcessDefinition().getId()); + + store.setProcessInstanceId(processInstance.getId()); + store.setProcessState(processInstance.getState()); + + piStoreDao.saveOrUpdate(store); + } + + /** + * Load a {@link ProcessInstance} with a certain id from the database. + * + * @param processInstanceId The process instance id + * @return The process instance corresponding to the id or {@code null} if no such object is + * found. + * @throws MOADatabaseException Thrown if an error occurs while accessing the database. + */ + private ProcessInstance loadProcessInstance(final String processInstanceId) throws EaafException { + + final ProcessInstanceStore piStore = piStoreDao.load(processInstanceId); + + if (piStore == null) { + return null; + } + + final ExecutionContext executionContext = + new ExecutionContextImpl(piStore.getProcessInstanceId()); + + final Map<String, Serializable> executionContextData = piStore.getExecutionContextData(); + for (final Entry<String, Serializable> el : executionContextData.entrySet()) { + executionContext.put(el.getKey(), el.getValue()); + } + + final ProcessInstance pi = new ProcessInstance( + processDefinitions.get(piStore.getProcessDefinitionId()), executionContext); + pi.setNextId(piStore.getNextTaskId()); + pi.setState(piStore.getProcessState()); + + return pi; + } + + /* + * (non-Javadoc) + * + * @see at.gv.egovernment.moa.id.process.ProcessEngine#deleteProcessInstance(java.lang.String) + */ + @Override + public void deleteProcessInstance(final String processInstanceId) + throws ProcessExecutionException { + if (StringUtils.isEmpty(processInstanceId)) { + throw new ProcessExecutionException( + "Unable to remove process instance: ProcessInstanceId is empty"); + + } + + try { + piStoreDao.remove(processInstanceId); + + } catch (final EaafException e) { + throw new ProcessExecutionException("Unable to remove process instance.", e); + + } + + } + + /** + * Finish a process-flow and remove any process-flow related information. + * + * @param pi current process instance + * @throws ProcessExecutionException In case of an process error + */ + private void processFinishEvent(final ProcessInstance pi) throws ProcessExecutionException { + log.info("Finishing process instance '{}'.", pi.getId()); + + try { + piStoreDao.remove(pi.getId()); + + } catch (final EaafException e) { + throw new ProcessExecutionException("Unable to remove process instance.", e); + + } + pi.setState(ProcessInstanceState.ENDED); + log.debug("Final process context: {}", pi.getExecutionContext().keySet()); + + } + + /** + * Perform some post-validation operations on process definition. + * + * <p> + * Like: check if all tasks that are defined are available on context + * </p> + * + * @param pd current process definition + * @throws ProcessDefinitionParserException In case of a parser error + */ + private void postValidationOfProcessDefintion(final ProcessDefinition pd) + throws ProcessDefinitionParserException { + try { + for (final TaskInfo task : pd.getTaskInfos().values()) { + createTaskInstance(task); + } + + } catch (final ProcessExecutionException e) { + log.error("Post-validation of process definition: {} find an error: {}", pd.getId(), + e.getMessage()); + throw new ProcessDefinitionParserException( + "Post-validation find an error in process definition:" + pd.getId(), e); + + } + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstance.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstance.java index 6db1dc7d..69683529 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstance.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstance.java @@ -1,190 +1,185 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process; import java.io.Serializable; import java.util.Date; - +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessDefinition; +import at.gv.egiz.eaaf.core.impl.idp.process.support.SecureRandomHolder; import org.apache.commons.lang3.RandomStringUtils; import org.apache.commons.lang3.time.DurationFormatUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; -import at.gv.egiz.eaaf.core.impl.idp.process.model.ProcessDefinition; -import at.gv.egiz.eaaf.core.impl.idp.process.support.SecureRandomHolder; - /** - * Represents a process being executed. The process instance provides information about the process and its state. - * + * Represents a process being executed. The process instance provides information about the process + * and its state. + * * @author tknall - * + * */ public class ProcessInstance implements Serializable { - private static final long serialVersionUID = 1L; - private static final int RND_ID_LENGTH = 22; - - private final ProcessDefinition processDefinition; - private String nextId; - private Date lru; - private final ExecutionContext executionContext; - private ProcessInstanceState state = ProcessInstanceState.NOT_STARTED; - - private final Logger log = LoggerFactory.getLogger(getClass()); - - /** - * Creates a new process instance, based on a given process definition and a - * given execution context. If the given execution context is {@code null} a new execution context will be created.<p/> - * The process instance id of the execution context will be newly generated if it is {@code null} in the execution context. - * - * @param processDefinition - * The process definition. - * @param executionContext - * The execution context (may be {@code null}). If {@code null} a new execution context will be created internally. - */ - ProcessInstance(ProcessDefinition processDefinition, ExecutionContext executionContext) { - this.processDefinition = processDefinition; - nextId = processDefinition.getStartEvent().getId(); - if (executionContext == null) { - executionContext = new ExecutionContextImpl(); - } - if (executionContext.getProcessInstanceId() == null) { - final String pdIdLocalPart = RandomStringUtils.random(RND_ID_LENGTH, 0, 0, true, true, null, - SecureRandomHolder.getInstance()); - executionContext.setProcessInstanceId(this.processDefinition.getId() + "-" + pdIdLocalPart); - } else { - log.debug("Using process instance id from execution context."); - } - log.debug("Creating process instance with id '{}'.", executionContext.getProcessInstanceId()); - this.executionContext = executionContext; - touch(); - } - - /** - * Returns the underlying process definition. - * - * @return The underlying process definition. - */ - ProcessDefinition getProcessDefinition() { - touch(); - return processDefinition; - } - - /** - * Returns the id of the process node to be executed next. - * - * @return The process node pointer indicating the process node to be executed next. - */ - public String getNextId() { - touch(); - return nextId; - } - - /** - * Sets the internal pointer to the process node to be executed next. - * - * @param nextId - * The process node id to be executed next. - */ - void setNextId(String nextId) { - touch(); - this.nextId = nextId; - } - - /** - * Returns the current state of the process instance. - * - * @return The current state. - */ - public ProcessInstanceState getState() { - touch(); - return state; - } - - /** - * Sets the current state of the process instance. - * - * @param state - * The current state. - */ - void setState(ProcessInstanceState state) { - touch(); - this.state = state; - } - - public String getId() { - touch(); - return executionContext.getProcessInstanceId(); - } - - /** - * Updates the last recently used date of the process instance. - */ - private void touch() { - lru = new Date(); - } - - /** - * Returns the date the process instance has been accessed last. - * - * @return The last recently used date. - */ - Date getLru() { - return lru; - } - - /** - * Returns the associated execution context. - * @return The execution context (never {@code null}). - */ - public ExecutionContext getExecutionContext() { - touch(); - return executionContext; - } - - @Override - public String toString() { - final StringBuilder builder = new StringBuilder(); - builder.append("ProcessInstance ["); - builder.append("id=").append(executionContext.getProcessInstanceId()); - builder.append(", idle since=").append( - DurationFormatUtils.formatDurationWords(new Date().getTime() - this.lru.getTime(), true, true)); - if (processDefinition != null) { - builder.append(", processDefinition.id="); - builder.append(processDefinition.getId()); - } - if (nextId != null) { - builder.append(", nextId="); - builder.append(nextId); - } - builder.append(", executionContext=").append(executionContext); - builder.append("]"); - return builder.toString(); - } + private static final long serialVersionUID = 1L; + private static final int RND_ID_LENGTH = 22; + + private final ProcessDefinition processDefinition; + private String nextId; + private Date lru; + private final ExecutionContext executionContext; + private ProcessInstanceState state = ProcessInstanceState.NOT_STARTED; + + + + /** + * Creates a new process instance, based on a given process definition and a given execution + * context. If the given execution context is {@code null} a new execution context will be + * created. + * <p/> + * The process instance id of the execution context will be newly generated if it is {@code null} + * in the execution context. + * + * @param processDefinition The process definition. + * @param executionContext The execution context (may be {@code null}). If {@code null} a new + * execution context will be created internally. + */ + ProcessInstance(final ProcessDefinition processDefinition, ExecutionContext executionContext) { + final Logger log = LoggerFactory.getLogger(getClass()); + + this.processDefinition = processDefinition; + nextId = processDefinition.getStartEvent().getId(); + if (executionContext == null) { + executionContext = new ExecutionContextImpl(); + } + if (executionContext.getProcessInstanceId() == null) { + final String pdIdLocalPart = RandomStringUtils.random(RND_ID_LENGTH, 0, 0, true, true, null, + SecureRandomHolder.getInstance()); + executionContext.setProcessInstanceId(this.processDefinition.getId() + "-" + pdIdLocalPart); + } else { + log.debug("Using process instance id from execution context."); + } + log.debug("Creating process instance with id '{}'.", executionContext.getProcessInstanceId()); + this.executionContext = executionContext; + touch(); + } + + /** + * Returns the underlying process definition. + * + * @return The underlying process definition. + */ + ProcessDefinition getProcessDefinition() { + touch(); + return processDefinition; + } + + /** + * Returns the id of the process node to be executed next. + * + * @return The process node pointer indicating the process node to be executed next. + */ + public String getNextId() { + touch(); + return nextId; + } + + /** + * Sets the internal pointer to the process node to be executed next. + * + * @param nextId The process node id to be executed next. + */ + void setNextId(final String nextId) { + touch(); + this.nextId = nextId; + } + + /** + * Returns the current state of the process instance. + * + * @return The current state. + */ + public ProcessInstanceState getState() { + touch(); + return state; + } + + /** + * Sets the current state of the process instance. + * + * @param state The current state. + */ + void setState(final ProcessInstanceState state) { + touch(); + this.state = state; + } + + public String getId() { + touch(); + return executionContext.getProcessInstanceId(); + } + + /** + * Updates the last recently used date of the process instance. + */ + private void touch() { + lru = new Date(); + } + + /** + * Returns the date the process instance has been accessed last. + * + * @return The last recently used date. + */ + Date getLru() { + return lru; + } + + /** + * Returns the associated execution context. + * + * @return The execution context (never {@code null}). + */ + public ExecutionContext getExecutionContext() { + touch(); + return executionContext; + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("ProcessInstance ["); + builder.append("id=").append(executionContext.getProcessInstanceId()); + builder.append(", idle since=").append(DurationFormatUtils + .formatDurationWords(new Date().getTime() - this.lru.getTime(), true, true)); + if (processDefinition != null) { + builder.append(", processDefinition.id="); + builder.append(processDefinition.getId()); + } + if (nextId != null) { + builder.append(", nextId="); + builder.append(nextId); + } + builder.append(", executionContext=").append(executionContext); + builder.append("]"); + return builder.toString(); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstanceState.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstanceState.java index 1abf5b86..e6bfa480 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstanceState.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/ProcessInstanceState.java @@ -1,56 +1,51 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process; /** * Represents a certain process instance state. + * * @author tknall * */ public enum ProcessInstanceState { - - /** - * Indicates that the process with this process instance has not yet been started. - */ - NOT_STARTED, - - /** - * Indicates that the process is currently running. - */ - STARTED, - - /** - * Indicates that the process has been suspended until being waken up by someonce calling {@code signal}. - */ - SUSPENDED, - - /** - * Indicates that the process has been completed. - */ - ENDED + + /** + * Indicates that the process with this process instance has not yet been started. + */ + NOT_STARTED, + + /** + * Indicates that the process is currently running. + */ + STARTED, + + /** + * Indicates that the process has been suspended until being waken up by someonce calling + * {@code signal}. + */ + SUSPENDED, + + /** + * Indicates that the process has been completed. + */ + ENDED } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStore.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStore.java index 0fee29e5..f1abaef3 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStore.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStore.java @@ -1,99 +1,91 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.dao; import java.io.Serializable; import java.util.Map; - import at.gv.egiz.eaaf.core.impl.idp.process.ProcessInstanceState; -public class ProcessInstanceStore implements Serializable{ +public class ProcessInstanceStore implements Serializable { + + private static final long serialVersionUID = -6147519767313903808L; + + /** + * A process instance identifier qualifies as natural primary key by satisfying these requirements. + * ("unique, constant, required"): + * <ul> + * <li>unique value</li> + * <li>never changes (immutable)</li> + * <li>never {@code null}</li> + * </ul> + */ - private static final long serialVersionUID = -6147519767313903808L; + private String processInstanceId; - /** - * A process instance identifier qualifies as natural primary key by satisfying these requirements - * ("unique, constant, required"): - * <ul> - * <li>unique value</li> - * <li>never changes (immutable)</li> - * <li>never {@code null}</li> - * </ul> - */ + private String processDefinitionId; - private String processInstanceId; + private String nextTaskId; - private String processDefinitionId; + private ProcessInstanceState processState; - private String nextTaskId; + private Map<String, Serializable> executionContextData; - private ProcessInstanceState processState; - - private Map<String, Serializable> executionContextData; - - public String getProcessInstanceId() { - return processInstanceId; - } + public String getProcessInstanceId() { + return processInstanceId; + } - public String getProcessDefinitionId() { - return processDefinitionId; - } + public String getProcessDefinitionId() { + return processDefinitionId; + } - public String getNextTaskId() { - return nextTaskId; - } + public String getNextTaskId() { + return nextTaskId; + } - public ProcessInstanceState getProcessState() { - return processState; - } + public ProcessInstanceState getProcessState() { + return processState; + } - @SuppressWarnings("unchecked") - public Map<String, Serializable> getExecutionContextData() { - return executionContextData; - } + @SuppressWarnings("unchecked") + public Map<String, Serializable> getExecutionContextData() { + return executionContextData; + } - public void setProcessInstanceId(String processInstanceId) { - this.processInstanceId = processInstanceId; - } + public void setProcessInstanceId(final String processInstanceId) { + this.processInstanceId = processInstanceId; + } - public void setProcessDefinitionId(String processDefinitionId) { - this.processDefinitionId = processDefinitionId; - } + public void setProcessDefinitionId(final String processDefinitionId) { + this.processDefinitionId = processDefinitionId; + } - public void setNextTaskId(String nextTaskId) { - this.nextTaskId = nextTaskId; - } + public void setNextTaskId(final String nextTaskId) { + this.nextTaskId = nextTaskId; + } - public void setProcessState(ProcessInstanceState processState) { - this.processState = processState; - } + public void setProcessState(final ProcessInstanceState processState) { + this.processState = processState; + } - public void setExecutionContextData(Map<String, Serializable> executionContextData) { - this.executionContextData = executionContextData; - } + public void setExecutionContextData(final Map<String, Serializable> executionContextData) { + this.executionContextData = executionContextData; + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDAOImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDAOImpl.java deleted file mode 100644 index 681c9707..00000000 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDAOImpl.java +++ /dev/null @@ -1,97 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eaaf.core.impl.idp.process.dao; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; - -import at.gv.egiz.eaaf.core.api.idp.process.ProcessInstanceStoreDAO; -import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; -import at.gv.egiz.eaaf.core.exceptions.EAAFException; - -/** - * Database backed implementation of the {@link ProcessInstanceStoreDAO} - * interface. - */ -@Service("ProcessInstanceStoreage") -public class ProcessInstanceStoreDAOImpl implements ProcessInstanceStoreDAO { - - private Logger log = LoggerFactory.getLogger(getClass()); - - @Autowired ITransactionStorage transactionStorage; - - @Override - public void saveOrUpdate(ProcessInstanceStore pIStore) throws EAAFException { - try { - transactionStorage.put(pIStore.getProcessInstanceId(), pIStore, -1); - log.debug("Store process instance with='{}' in the database.", pIStore.getProcessInstanceId()); - - } catch (EAAFException e) { - log.warn("ProcessInstanceStore could not be persisted to the database."); - throw e; - } - } - - @Override - public ProcessInstanceStore load(String processInstanceId) throws EAAFException { - log.debug("Retrieve the ProcessInstanceStore for id='{}' from the database.", processInstanceId); - ProcessInstanceStore result = null; - try { - result = transactionStorage.get(processInstanceId, ProcessInstanceStore.class); - - } catch (Exception e) { - log.error("There are multiple persisted processes with the same process instance id '{}'", - processInstanceId); - - throw e; - } - - if (result != null) { - log.debug("Found process instance store for instance '{}'.", processInstanceId); - - } else { - log.debug("Unable to find process instance store for instance '{}'.", processInstanceId); - - } - - return result; - } - - @Override - public void remove(String processInstanceId) throws EAAFException { - - log.debug("Delete the ProcessInstanceStore for id='{}' from the database.", processInstanceId); - - if (transactionStorage.containsKey(processInstanceId)) - transactionStorage.remove(processInstanceId); - else - log.trace("ProcessInstanceStore for id='{}' was not found and could therefore not be deleted.", processInstanceId); - } - -} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDaoImpl.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDaoImpl.java new file mode 100644 index 00000000..06c8cc1a --- /dev/null +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/dao/ProcessInstanceStoreDaoImpl.java @@ -0,0 +1,94 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.gv.egiz.eaaf.core.impl.idp.process.dao; + +import at.gv.egiz.eaaf.core.api.idp.process.ProcessInstanceStoreDao; +import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage; +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * Database backed implementation of the {@link ProcessInstanceStoreDao} interface. + */ +@Service("ProcessInstanceStoreage") +public class ProcessInstanceStoreDaoImpl implements ProcessInstanceStoreDao { + + private final Logger log = LoggerFactory.getLogger(getClass()); + + @Autowired + ITransactionStorage transactionStorage; + + @Override + public void saveOrUpdate(final ProcessInstanceStore piStore) throws EaafException { + try { + transactionStorage.put(piStore.getProcessInstanceId(), piStore, -1); + log.debug("Store process instance with='{}' in the database.", + piStore.getProcessInstanceId()); + + } catch (final EaafException e) { + log.warn("ProcessInstanceStore could not be persisted to the database."); + throw e; + } + } + + @Override + public ProcessInstanceStore load(final String processInstanceId) throws EaafException { + log.debug("Retrieve the ProcessInstanceStore for id='{}' from the database.", + processInstanceId); + ProcessInstanceStore result = null; + try { + result = transactionStorage.get(processInstanceId, ProcessInstanceStore.class); + + } catch (final Exception e) { + log.error("There are multiple persisted processes with the same process instance id '{}'", + processInstanceId); + + throw e; + } + + if (result != null) { + log.debug("Found process instance store for instance '{}'.", processInstanceId); + + } else { + log.debug("Unable to find process instance store for instance '{}'.", processInstanceId); + + } + + return result; + } + + @Override + public void remove(final String processInstanceId) throws EaafException { + + log.debug("Delete the ProcessInstanceStore for id='{}' from the database.", processInstanceId); + + if (transactionStorage.containsKey(processInstanceId)) { + transactionStorage.remove(processInstanceId); + } else { + log.trace( + "ProcessInstanceStore for id='{}' was not found and could therefore not be deleted.", + processInstanceId); + } + } + +} diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/EndEvent.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/EndEvent.java index 8657d0dc..48919ded 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/EndEvent.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/EndEvent.java @@ -1,68 +1,60 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.model; import java.io.Serializable; - import org.apache.commons.collections4.CollectionUtils; /** * Represents an end event. Process execution terminates when an end event is reached. - * + * * @author tknall */ public class EndEvent extends ProcessNode implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("EndEvent ["); - if (getId() != null) { - builder.append("id="); - builder.append(getId()); - } - if (CollectionUtils.isNotEmpty(getIncomingTransitions())) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("incomingTransitions="); - builder.append(getIncomingTransitions()); - } - if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("outgoingTransitions="); - builder.append(getOutgoingTransitions()); - } - builder.append("]"); - return builder.toString(); - } + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("EndEvent ["); + if (getId() != null) { + builder.append("id="); + builder.append(getId()); + } + if (CollectionUtils.isNotEmpty(getIncomingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("incomingTransitions="); + builder.append(getIncomingTransitions()); + } + if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("outgoingTransitions="); + builder.append(getOutgoingTransitions()); + } + builder.append("]"); + return builder.toString(); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessDefinition.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessDefinition.java index b7caef7a..3ab68266 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessDefinition.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessDefinition.java @@ -1,184 +1,177 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.model; +import java.io.Serializable; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; - import at.gv.egiz.eaaf.core.impl.idp.process.ProcessDefinitionParser; /** - * Represents a single process definition containing + * Represents a single process definition containing. * <ul> * <li>a {@link StartEvent},</li> * <li>one or more {@linkplain TaskInfo Tasks},</li> * <li>one or more {@linkplain EndEvent EndEvents} and</li> * <li>some {@linkplain Transition Transitions} linking StartEvents, Tasks and EndEvents. * </ul> - * + * * @author tknall - * + * */ -public class ProcessDefinition { - - private String id; - private StartEvent startEvent; - private Map<String, TaskInfo> taskInfos = new LinkedHashMap<>(); - private Map<String, EndEvent> endEvents = new LinkedHashMap<>(); - - /** - * Returns the unique identifier of the process definition. - * - * @return The unique identifier (never {@code null} if process definition comes from - * {@link ProcessDefinitionParser}). - */ - public String getId() { - return id; - } - - /** - * Sets the unique identifier of the process definition. - * - * @param id - * The unique identifier. - */ - public void setId(String id) { - this.id = id; - } - - /** - * Returns the start event of the process definition. - * - * @return The start event (never {@code null} if process definition comes from {@link ProcessDefinitionParser}). - */ - public StartEvent getStartEvent() { - return startEvent; - } - - /** - * Sets the start event of the process definition. - * - * @param startEvent - * The start event. - */ - public void setStartEvent(StartEvent startEvent) { - this.startEvent = startEvent; - } - - /** - * Returns a map containing the tasks of the process definition. - * - * @return The tasks (map is never {@code null} if process definition comes from {@link ProcessDefinitionParser}). - */ - public Map<String, TaskInfo> getTaskInfos() { - return taskInfos; - } - - /** - * Sets the map containing the tasks. - * - * @param taskInfos - * The map containing the tasks. - */ - public void setTaskInfos(Map<String, TaskInfo> taskInfos) { - this.taskInfos = taskInfos; - } - - /** - * Returns a map containing the end events of the process description. - * - * @return The map containing the end events (map is never {@code null} if process definition comes from - * {@link ProcessDefinitionParser}). - */ - public Map<String, EndEvent> getEndEvents() { - return endEvents; - } - - /** - * Sets a map containing the end events of the process description. - * - * @param endEvents - * The map containing the end events. - */ - public void setEndEvents(Map<String, EndEvent> endEvents) { - this.endEvents = endEvents; - } - - /** - * Returns the process node associated with the given {@code id}. - * - * @param id - * The identifier of the process node. - * @return The process node (may be {code null} when no process node with the given {@code id} exists). - */ - public ProcessNode getProcessNode(String id) { - Objects.requireNonNull(id, "Identifier must not be null."); - if (startEvent != null && id.equals(startEvent.getId())) { - return startEvent; - } - TaskInfo task = taskInfos.get(id); - if (task != null) { - return task; - } - return endEvents.get(id); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (id != null) { - builder.append("id="); - builder.append(id); - } - if (startEvent != null) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("startEvent="); - builder.append(startEvent); - } - if (taskInfos != null && !taskInfos.isEmpty()) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("tasksInfos="); - builder.append(taskInfos.values()); - } - if (endEvents != null && !endEvents.isEmpty()) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("endEvents="); - builder.append(endEvents.values()); - } - builder.insert(0, "ProcessDefinition ["); - builder.append("]"); - return builder.toString(); - } +public class ProcessDefinition implements Serializable { + + private static final long serialVersionUID = 7896697967510445442L; + + private String id; + private StartEvent startEvent; + private Map<String, TaskInfo> taskInfos = new LinkedHashMap<>(); + private Map<String, EndEvent> endEvents = new LinkedHashMap<>(); + + /** + * Returns the unique identifier of the process definition. + * + * @return The unique identifier (never {@code null} if process definition comes from + * {@link ProcessDefinitionParser}). + */ + public String getId() { + return id; + } + + /** + * Sets the unique identifier of the process definition. + * + * @param id The unique identifier. + */ + public void setId(final String id) { + this.id = id; + } + + /** + * Returns the start event of the process definition. + * + * @return The start event (never {@code null} if process definition comes from + * {@link ProcessDefinitionParser}). + */ + public StartEvent getStartEvent() { + return startEvent; + } + + /** + * Sets the start event of the process definition. + * + * @param startEvent The start event. + */ + public void setStartEvent(final StartEvent startEvent) { + this.startEvent = startEvent; + } + + /** + * Returns a map containing the tasks of the process definition. + * + * @return The tasks (map is never {@code null} if process definition comes from + * {@link ProcessDefinitionParser}). + */ + public Map<String, TaskInfo> getTaskInfos() { + return taskInfos; + } + + /** + * Sets the map containing the tasks. + * + * @param taskInfos The map containing the tasks. + */ + public void setTaskInfos(final Map<String, TaskInfo> taskInfos) { + this.taskInfos = taskInfos; + } + + /** + * Returns a map containing the end events of the process description. + * + * @return The map containing the end events (map is never {@code null} if process definition + * comes from {@link ProcessDefinitionParser}). + */ + public Map<String, EndEvent> getEndEvents() { + return endEvents; + } + + /** + * Sets a map containing the end events of the process description. + * + * @param endEvents The map containing the end events. + */ + public void setEndEvents(final Map<String, EndEvent> endEvents) { + this.endEvents = endEvents; + } + + /** + * Returns the process node associated with the given {@code id}. + * + * @param id The identifier of the process node. + * @return The process node (may be {code null} when no process node with the given {@code id} + * exists). + */ + public ProcessNode getProcessNode(final String id) { + Objects.requireNonNull(id, "Identifier must not be null."); + if (startEvent != null && id.equals(startEvent.getId())) { + return startEvent; + } + final TaskInfo task = taskInfos.get(id); + if (task != null) { + return task; + } + return endEvents.get(id); + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + if (id != null) { + builder.append("id="); + builder.append(id); + } + if (startEvent != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("startEvent="); + builder.append(startEvent); + } + if (taskInfos != null && !taskInfos.isEmpty()) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("tasksInfos="); + builder.append(taskInfos.values()); + } + if (endEvents != null && !endEvents.isEmpty()) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("endEvents="); + builder.append(endEvents.values()); + } + builder.insert(0, "ProcessDefinition ["); + builder.append("]"); + return builder.toString(); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessNode.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessNode.java index 7964fa47..92858edf 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessNode.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/ProcessNode.java @@ -1,95 +1,95 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.model; import java.util.ArrayList; import java.util.List; - import at.gv.egiz.eaaf.core.impl.idp.process.ProcessDefinitionParser; /** * Represents a {@link StartEvent}, an {@link EndEvent} or a {@linkplain TaskInfo Task}. + * * @author tknall * */ public abstract class ProcessNode { - private String id; - private List<Transition> outgoingTransitions = new ArrayList<>(); - private List<Transition> incomingTransitions = new ArrayList<>(); + private String id; + private List<Transition> outgoingTransitions = new ArrayList<>(); + private List<Transition> incomingTransitions = new ArrayList<>(); + + /** + * Returns the unique identifier of the process node. + * + * @return The unique identifier (never {@code null} if process node comes from a process + * definition from {@link ProcessDefinitionParser}). + */ + public String getId() { + return id; + } - /** - * Returns the unique identifier of the process node. - * - * @return The unique identifier (never {@code null} if process node comes from a process definition from - * {@link ProcessDefinitionParser}). - */ - public String getId() { - return id; - } + /** + * Sets the unique identifier of the process node. + * + * @param id The unique identifier. + */ + public void setId(final String id) { + this.id = id; + } - /** - * Sets the unique identifier of the process node. - * @param id The unique identifier. - */ - public void setId(String id) { - this.id = id; - } + /** + * Returns a list of transitions pointing from this process node to another one. + * + * @return A list of transitions (never {@code null} if process node comes from a process + * definition from {@link ProcessDefinitionParser}). + */ + public List<Transition> getOutgoingTransitions() { + return outgoingTransitions; + } - /** - * Returns a list of transitions pointing from this process node to another one. - * @return A list of transitions (never {@code null} if process node comes from a process definition from {@link ProcessDefinitionParser}). - */ - public List<Transition> getOutgoingTransitions() { - return outgoingTransitions; - } + /** + * Sets the list of transitions pointing from this process node to another one. + * + * @param outgoingTransitions The list of transitions originating from this process node. + */ + public void setOutgoingTransitions(final List<Transition> outgoingTransitions) { + this.outgoingTransitions = outgoingTransitions; + } - /** - * Sets the list of transitions pointing from this process node to another one. - * @param outgoingTransitions The list of transitions originating from this process node. - */ - public void setOutgoingTransitions(List<Transition> outgoingTransitions) { - this.outgoingTransitions = outgoingTransitions; - } + /** + * Returns a list of transitions pointing from another process node to this one. + * + * @return A list of transitions (never {@code null} if process node comes from a process + * definition from {@link ProcessDefinitionParser}). + */ + public List<Transition> getIncomingTransitions() { + return incomingTransitions; + } - /** - * Returns a list of transitions pointing from another process node to this one. - * @return A list of transitions (never {@code null} if process node comes from a process definition from {@link ProcessDefinitionParser}). - */ - public List<Transition> getIncomingTransitions() { - return incomingTransitions; - } + /** + * Sets the list of transitions pointing from another process node to this one. + * + * @param incomingTransitions A list of transitions pointing to this process node. + */ + public void setIncomingTransitions(final List<Transition> incomingTransitions) { + this.incomingTransitions = incomingTransitions; + } - /** - * Sets the list of transitions pointing from another process node to this one. - * @param incomingTransitions A list of transitions pointing to this process node. - */ - public void setIncomingTransitions(List<Transition> incomingTransitions) { - this.incomingTransitions = incomingTransitions; - } - } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/StartEvent.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/StartEvent.java index 8e358b69..698312c7 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/StartEvent.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/StartEvent.java @@ -1,71 +1,63 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.model; import java.io.Serializable; - import org.apache.commons.collections4.CollectionUtils; /** - * Represents a start event. Each process description contains a single start event. Process execution starts with a - * start event. - * + * Represents a start event. Each process description contains a single start event. Process + * execution starts with a start event. + * * @author tknall - * + * */ public class StartEvent extends ProcessNode implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("StartEvent ["); - if (getId() != null) { - builder.append("id="); - builder.append(getId()); - } - if (CollectionUtils.isNotEmpty(getIncomingTransitions())) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("incomingTransitions="); - builder.append(getIncomingTransitions()); - } - if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("outgoingTransitions="); + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("StartEvent ["); + if (getId() != null) { + builder.append("id="); + builder.append(getId()); + } + if (CollectionUtils.isNotEmpty(getIncomingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("incomingTransitions="); + builder.append(getIncomingTransitions()); + } + if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("outgoingTransitions="); - builder.append(getOutgoingTransitions()); - } - builder.append("]"); - return builder.toString(); - } + builder.append(getOutgoingTransitions()); + } + builder.append("]"); + return builder.toString(); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/TaskInfo.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/TaskInfo.java index b98045c5..9e384b4c 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/TaskInfo.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/TaskInfo.java @@ -1,120 +1,117 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. + */ + package at.gv.egiz.eaaf.core.impl.idp.process.model; import java.io.Serializable; - -import org.apache.commons.collections4.CollectionUtils; - import at.gv.egiz.eaaf.core.api.idp.process.Task; +import org.apache.commons.collections4.CollectionUtils; /** * Represents information about a single task to be performed upon process execution. + * * @author tknall * */ public class TaskInfo extends ProcessNode implements Serializable { - private static final long serialVersionUID = 1L; - private static final boolean DEFAULT_ASYNC = false; - - private String taskImplementingClass; - private boolean async = DEFAULT_ASYNC; - - /** - * Determines if the task is marked asynchronous ({@code true}) or synchronous ({@code false}). - * @return A flag indicating if the task should be executed asynchronously or synchronously. (Default: {@code false}) - */ - public boolean isAsync() { - return async; - } + private static final long serialVersionUID = 1L; + private static final boolean DEFAULT_ASYNC = false; + + private String taskImplementingClass; + private boolean async = DEFAULT_ASYNC; + + /** + * Determines if the task is marked asynchronous ({@code true}) or synchronous ({@code false}). + * + * @return A flag indicating if the task should be executed asynchronously or synchronously. + * (Default: {@code false}) + */ + public boolean isAsync() { + return async; + } - /** - * Marks a task to executed asynchronously ({@code true}) or synchronously ({@code false}). - * @param async The flag. - */ - public void setAsync(boolean async) { - this.async = async; - } + /** + * Marks a task to executed asynchronously ({@code true}) or synchronously ({@code false}). + * + * @param async The flag. + */ + public void setAsync(final boolean async) { + this.async = async; + } - /** - * Returns the class that implements the actual task (must implement {@link Task}). - * @return The task implementing class. - */ - public String getTaskImplementingClass() { - return taskImplementingClass; - } + /** + * Returns the class that implements the actual task (must implement {@link Task}). + * + * @return The task implementing class. + */ + public String getTaskImplementingClass() { + return taskImplementingClass; + } - /** - * Sets the class that implements the actual task (must implement {@link Task}). - * @param taskImplementingClass The task implementing class. - */ - public void setTaskImplementingClass(String taskImplementingClass) { - this.taskImplementingClass = taskImplementingClass; - } + /** + * Sets the class that implements the actual task (must implement {@link Task}). + * + * @param taskImplementingClass The task implementing class. + */ + public void setTaskImplementingClass(final String taskImplementingClass) { + this.taskImplementingClass = taskImplementingClass; + } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (getId() != null) { - builder.append("id="); - builder.append(getId()); - } - if (async != DEFAULT_ASYNC) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("async="); - builder.append(async); - } - if (taskImplementingClass != null) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("taskImplementingClass="); - builder.append(taskImplementingClass); - } - if (CollectionUtils.isNotEmpty(getIncomingTransitions())) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("incomingTransitions="); - builder.append(getIncomingTransitions()); - } - if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("outgoingTransitions="); - builder.append(getOutgoingTransitions()); - } - builder.insert(0, "TaskInfo ["); - builder.append("]"); - return builder.toString(); - } + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + if (getId() != null) { + builder.append("id="); + builder.append(getId()); + } + if (async != DEFAULT_ASYNC) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("async="); + builder.append(async); + } + if (taskImplementingClass != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("taskImplementingClass="); + builder.append(taskImplementingClass); + } + if (CollectionUtils.isNotEmpty(getIncomingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("incomingTransitions="); + builder.append(getIncomingTransitions()); + } + if (CollectionUtils.isNotEmpty(getOutgoingTransitions())) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("outgoingTransitions="); + builder.append(getOutgoingTransitions()); + } + builder.insert(0, "TaskInfo ["); + builder.append("]"); + return builder.toString(); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/Transition.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/Transition.java index 542ea7a8..4c7b70f0 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/Transition.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/model/Transition.java @@ -1,162 +1,150 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.model; import java.io.Serializable; - import at.gv.egiz.eaaf.core.impl.idp.process.ProcessDefinitionParser; /** * Represents a single transition from a {@link StartEvent} or {@linkplain TaskInfo Task} to another * {@linkplain TaskInfo Task} or {@link EndEvent}. - * + * * @author tknall - * + * */ public class Transition implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - private String id; - private String conditionExpression; - private ProcessNode from; - private ProcessNode to; + private String id; + private String conditionExpression; + private ProcessNode from; + private ProcessNode to; - /** - * Returns the process node (effectively a {@link StartEvent} or {@linkplain TaskInfo Task}) the transition is - * pointing from. - * - * @return The transition's source process node (never {@code null} if transition comes from a process definition - * from {@link ProcessDefinitionParser}). - */ - public ProcessNode getFrom() { - return from; - } + /** + * Returns the process node (effectively a {@link StartEvent} or {@linkplain TaskInfo Task}) the + * transition is pointing from. + * + * @return The transition's source process node (never {@code null} if transition comes from a + * process definition from {@link ProcessDefinitionParser}). + */ + public ProcessNode getFrom() { + return from; + } - /** - * Sets the process node the transition is pointing from. - * - * @param from - * The transition's source process node. - */ - public void setFrom(ProcessNode from) { - this.from = from; - } + /** + * Sets the process node the transition is pointing from. + * + * @param from The transition's source process node. + */ + public void setFrom(final ProcessNode from) { + this.from = from; + } - /** - * Returns the process node (effectively a {@linkplain TaskInfo Task} or {@link EndEvent}) the transition is - * pointing to. - * - * @return The transition's destination process node (never {@code null} if transition comes from a process - * definition from {@link ProcessDefinitionParser}). - */ - public ProcessNode getTo() { - return to; - } + /** + * Returns the process node (effectively a {@linkplain TaskInfo Task} or {@link EndEvent}) the + * transition is pointing to. + * + * @return The transition's destination process node (never {@code null} if transition comes from + * a process definition from {@link ProcessDefinitionParser}). + */ + public ProcessNode getTo() { + return to; + } - /** - * Sets the process node the transition is pointing to. - * - * @param to - * The transition's destination process node. - */ - public void setTo(ProcessNode to) { - this.to = to; - } + /** + * Sets the process node the transition is pointing to. + * + * @param to The transition's destination process node. + */ + public void setTo(final ProcessNode to) { + this.to = to; + } - /** - * Returns the unique identifier of the transition. - * - * @return The unique identifier (may be {@code null}). - */ - public String getId() { - return id; - } + /** + * Returns the unique identifier of the transition. + * + * @return The unique identifier (may be {@code null}). + */ + public String getId() { + return id; + } - /** - * Sets the unique identifier of the transition. - * - * @param id - * The unique identifier. - */ - public void setId(String id) { - this.id = id; - } + /** + * Sets the unique identifier of the transition. + * + * @param id The unique identifier. + */ + public void setId(final String id) { + this.id = id; + } - /** - * Returns the condition expression for this transition. - * - * @return The condition expression (may be {@code null}). - */ - public String getConditionExpression() { - return conditionExpression; - } + /** + * Returns the condition expression for this transition. + * + * @return The condition expression (may be {@code null}). + */ + public String getConditionExpression() { + return conditionExpression; + } - /** - * Sets the condition expression for this transition. - * - * @param conditionExpression - * The condition expression. - */ - public void setConditionExpression(String conditionExpression) { - this.conditionExpression = conditionExpression; - } + /** + * Sets the condition expression for this transition. + * + * @param conditionExpression The condition expression. + */ + public void setConditionExpression(final String conditionExpression) { + this.conditionExpression = conditionExpression; + } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - if (id != null) { - builder.append("id="); - builder.append(id); - } - if (from != null) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("from.id="); - builder.append(from.getId()); - } - if (to != null) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("to.id="); - builder.append(to.getId()); - } - if (conditionExpression != null) { - if (builder.length() > 0) { - builder.append(", "); - } - builder.append("conditionExpression="); - builder.append(conditionExpression); - } - builder.insert(0, "Transition ["); - builder.append("]"); - return builder.toString(); - } + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + if (id != null) { + builder.append("id="); + builder.append(id); + } + if (from != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("from.id="); + builder.append(from.getId()); + } + if (to != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("to.id="); + builder.append(to.getId()); + } + if (conditionExpression != null) { + if (builder.length() > 0) { + builder.append(", "); + } + builder.append("conditionExpression="); + builder.append(conditionExpression); + } + builder.insert(0, "Transition ["); + builder.append("]"); + return builder.toString(); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/spring/SpringExpressionEvaluator.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/spring/SpringExpressionEvaluator.java index a91963e8..fc01463e 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/spring/SpringExpressionEvaluator.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/spring/SpringExpressionEvaluator.java @@ -1,35 +1,29 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.spring; import java.util.Objects; - import javax.annotation.PostConstruct; - +import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext; +import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluator; +import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition; import org.apache.commons.lang3.BooleanUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,47 +35,44 @@ import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; -import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext; -import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluator; -import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition; - /** - * Expression evaluator for processing {@link Transition} conditions allowing to reference Spring beans from the - * application context. - * + * Expression evaluator for processing {@link Transition} conditions allowing to reference Spring + * beans from the application context. + * * @author tknall - * + * */ public class SpringExpressionEvaluator implements ExpressionEvaluator { - private Logger log = LoggerFactory.getLogger(getClass()); - private ExpressionParser parser = new SpelExpressionParser(); - private StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ExpressionParser parser = new SpelExpressionParser(); + private final StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); - @Autowired(required = false) - private ApplicationContext ctx; + @Autowired(required = false) + private ApplicationContext ctx; - @PostConstruct - private void init() { - if (ctx != null) { - evaluationContext.setBeanResolver(new BeanFactoryResolver(ctx)); - } - } + @PostConstruct + private void init() { + if (ctx != null) { + evaluationContext.setBeanResolver(new BeanFactoryResolver(ctx)); + } + } - @Override - public boolean evaluate(ExpressionEvaluationContext expressionContext, String expression) { - Objects.requireNonNull(expression, "Expression must not be null."); - log.trace("Evaluating '{}'.", expression); + @Override + public boolean evaluate(final ExpressionEvaluationContext expressionContext, + final String expression) { + Objects.requireNonNull(expression, "Expression must not be null."); + log.trace("Evaluating '{}'.", expression); - Expression expr = parser.parseExpression(expression); - Boolean result = expr.getValue(evaluationContext, expressionContext, Boolean.class); - if (result == null) { - log.warn("Evaluation of '{}' results in null-value.", expression); - } else { - log.debug("Expression '{}' -> {}", expression, result); - } + final Expression expr = parser.parseExpression(expression); + final Boolean result = expr.getValue(evaluationContext, expressionContext, Boolean.class); + if (result == null) { + log.warn("Evaluation of '{}' results in null-value.", expression); + } else { + log.debug("Expression '{}' -> {}", expression, result); + } - return BooleanUtils.isTrue(result); - } + return BooleanUtils.isTrue(result); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractAuthSourceServlet.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractAuthSourceServlet.java index 4b007c4c..cc899641 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractAuthSourceServlet.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractAuthSourceServlet.java @@ -1,34 +1,29 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.springweb; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; - +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine; +import at.gv.egiz.eaaf.core.impl.idp.process.ProcessInstance; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.BeansException; import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -36,107 +31,95 @@ import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.support.WebApplicationContextUtils; -import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; -import at.gv.egiz.eaaf.core.api.idp.process.ProcessEngine; -import at.gv.egiz.eaaf.core.impl.idp.process.ProcessInstance; - /** - * Abstract HttpServlet that provides means for retrieving the process engine (Spring Web required) as well as - * retrieving the underlying process instance and execution context evaluating a certain request parameter. - * + * Abstract HttpServlet that provides means for retrieving the process engine (Spring Web required) + * as well as retrieving the underlying process instance and execution context evaluating a certain + * request parameter. + * * @author tknall - * + * */ public abstract class AbstractAuthSourceServlet extends HttpServlet { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; + + private ProcessEngine processEngine; - private ProcessEngine processEngine; - - /** - * Returns the name of the request parameter representing the respective instance id. - * <p/>Default is {@code processInstanceId}. - * @return The request parameter name. - */ - public String getProcessInstanceIdParameterName() { - return "processInstanceId"; - } + /** + * Returns the name of the request parameter representing the respective instance id. + * <p/> + * Default is {@code processInstanceId}. + * + * @return The request parameter name. + */ + public String getProcessInstanceIdParameterName() { + return "processInstanceId"; + } - /** - * Returns the underlying process engine instance. - * - * @return The process engine (never {@code null}). - * @throws NoSuchBeanDefinitionException - * if no {@link ProcessEngine} bean was found. - * @throws NoUniqueBeanDefinitionException - * if more than one {@link ProcessEngine} bean was found. - * @throws BeansException - * if a problem getting the {@link ProcessEngine} bean occurred. - * @throws IllegalStateException - * if the Spring WebApplicationContext was not found, which means that the servlet is used outside a - * Spring web environment. - */ - public synchronized ProcessEngine getProcessEngine() { - if (processEngine == null) { - WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); - if (ctx == null) { - throw new IllegalStateException( - "Unable to find Spring WebApplicationContext. Servlet needs to be executed within a Spring web environment."); - } - processEngine = ctx.getBean(ProcessEngine.class); - } - return processEngine; - } + /** + * Returns the underlying process engine instance. + * + * @return The process engine (never {@code null}). + * @throws NoSuchBeanDefinitionException if no {@link ProcessEngine} bean was found. + * @throws NoUniqueBeanDefinitionException if more than one {@link ProcessEngine} bean was found. + * @throws BeansException if a problem getting the {@link ProcessEngine} bean occurred. + * @throws IllegalStateException if the Spring WebApplicationContext was not found, which means + * that the servlet is used outside a Spring web environment. + */ + public synchronized ProcessEngine getProcessEngine() { + if (processEngine == null) { + final WebApplicationContext ctx = + WebApplicationContextUtils.getWebApplicationContext(getServletContext()); + if (ctx == null) { + throw new IllegalStateException( + "Unable to find Spring WebApplicationContext. " + + "Servlet needs to be executed within a Spring web environment."); + } + processEngine = ctx.getBean(ProcessEngine.class); + } + return processEngine; + } - /** - * Retrieves the process instance referenced by the request parameter {@link #getProcessInstanceIdParameterName()}. - * - * @param request - * The HttpServletRequest. - * @return The process instance (never {@code null}). - * @throws NoSuchBeanDefinitionException - * if no {@link ProcessEngine} bean was found. - * @throws NoUniqueBeanDefinitionException - * if more than one {@link ProcessEngine} bean was found. - * @throws BeansException - * if a problem getting the {@link ProcessEngine} bean occurred. - * @throws IllegalStateException - * if the Spring WebApplicationContext was not found, which means that the servlet is used outside a - * Spring web environment. - * @throws IllegalArgumentException - * in case the process instance id referenced by the request parameter - * {@link #getProcessInstanceIdParameterName()} does not exist. - */ - public ProcessInstance getProcessInstance(HttpServletRequest request) { - String processInstanceId = StringUtils.trimToNull(request.getParameter(getProcessInstanceIdParameterName())); - if (processInstanceId == null) { - throw new IllegalArgumentException("Missing request parameter '" + getProcessInstanceIdParameterName() + "'."); - } - return getProcessEngine().getProcessInstance(processInstanceId); - } + /** + * Retrieves the process instance referenced by the request parameter + * {@link #getProcessInstanceIdParameterName()}. + * + * @param request The HttpServletRequest. + * @return The process instance (never {@code null}). + * @throws NoSuchBeanDefinitionException if no {@link ProcessEngine} bean was found. + * @throws NoUniqueBeanDefinitionException if more than one {@link ProcessEngine} bean was found. + * @throws BeansException if a problem getting the {@link ProcessEngine} bean occurred. + * @throws IllegalStateException if the Spring WebApplicationContext was not found, which means + * that the servlet is used outside a Spring web environment. + * @throws IllegalArgumentException in case the process instance id referenced by the request + * parameter {@link #getProcessInstanceIdParameterName()} does not exist. + */ + public ProcessInstance getProcessInstance(final HttpServletRequest request) { + final String processInstanceId = + StringUtils.trimToNull(request.getParameter(getProcessInstanceIdParameterName())); + if (processInstanceId == null) { + throw new IllegalArgumentException( + "Missing request parameter '" + getProcessInstanceIdParameterName() + "'."); + } + return getProcessEngine().getProcessInstance(processInstanceId); + } - /** - * Retrieves the execution context for the respective process instance referenced by the request parameter - * {@link #getProcessInstanceIdParameterName()}. - * - * @param request - * The HttpServletRequest. - * @return The execution context (never {@code null}). - * @throws NoSuchBeanDefinitionException - * if no {@link ProcessEngine} bean was found. - * @throws NoUniqueBeanDefinitionException - * if more than one {@link ProcessEngine} bean was found. - * @throws BeansException - * if a problem getting the {@link ProcessEngine} bean occurred. - * @throws IllegalStateException - * if the Spring WebApplicationContext was not found, which means that the servlet is used outside a - * Spring web environment. - * @throws IllegalArgumentException - * in case the process instance id referenced by the request parameter - * {@link #getProcessInstanceIdParameterName()} does not exist. - */ - public ExecutionContext getExecutionContext(HttpServletRequest request) { - return getProcessInstance(request).getExecutionContext(); - } + /** + * Retrieves the execution context for the respective process instance referenced by the request + * parameter {@link #getProcessInstanceIdParameterName()}. + * + * @param request The HttpServletRequest. + * @return The execution context (never {@code null}). + * @throws NoSuchBeanDefinitionException if no {@link ProcessEngine} bean was found. + * @throws NoUniqueBeanDefinitionException if more than one {@link ProcessEngine} bean was found. + * @throws BeansException if a problem getting the {@link ProcessEngine} bean occurred. + * @throws IllegalStateException if the Spring WebApplicationContext was not found, which means + * that the servlet is used outside a Spring web environment. + * @throws IllegalArgumentException in case the process instance id referenced by the request + * parameter {@link #getProcessInstanceIdParameterName()} does not exist. + */ + public ExecutionContext getExecutionContext(final HttpServletRequest request) { + return getProcessInstance(request).getExecutionContext(); + } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractTask.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractTask.java index b7a20d71..02db6686 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractTask.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/AbstractTask.java @@ -1,50 +1,42 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.springweb; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; - -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; -import org.springframework.web.filter.RequestContextFilter; - import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.api.idp.process.Task; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; +import org.springframework.web.filter.RequestContextFilter; /** - * Abstract task implementation providing {@link HttpServletRequest} and {@link HttpServletResponse}. + * Abstract task implementation providing {@link HttpServletRequest} and + * {@link HttpServletResponse}. * <p/> - * Note that this abstract task requires the Spring (web) framework including a {@link RequestContextFilter} to be set - * within {@code web.xml}. - * + * Note that this abstract task requires the Spring (web) framework including a + * {@link RequestContextFilter} to be set within {@code web.xml}. + * * <pre> * ... * <filter> @@ -57,69 +49,72 @@ import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; * </filter-mapping> * ... * </pre> - * + * * @author tknall * @author tlenz - * + * */ public abstract class AbstractTask implements Task { - /** - * Executes the task providing the underlying {@link ExecutionContext} {@code executionContext} as well as the - * respective {@link HttpServletRequest} and {@link HttpServletResponse}. - * - * @param executionContext - * The execution context (never {@code null}). - * @param request - * The HttpServletRequest (never {@code null}). - * @param response - * The HttpServletResponse (never {@code null}). - * @throws IllegalStateException - * Thrown in case the task is nur being run within the required environment. Refer to javadoc for - * further information. - * @throws Exception - * Thrown in case of error executing the task. - */ - public abstract void execute(ExecutionContext executionContext, HttpServletRequest request, - HttpServletResponse response) throws TaskExecutionException; + @Override + public IRequest execute(final IRequest pendingReq, final ExecutionContext executionContext) + throws TaskExecutionException { + final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null && requestAttributes instanceof ServletRequestAttributes) { + final HttpServletRequest request = + ((ServletRequestAttributes) requestAttributes).getRequest(); + final HttpServletResponse response = + ((ServletRequestAttributes) requestAttributes).getResponse(); + if (request == null || response == null) { + throw new IllegalStateException( + "Spring's RequestContextHolder did not provide HttpServletResponse. " + + "Did you forget to set the required " + + "org.springframework.web.filter.RequestContextFilter in your web.xml."); + } + return internalExecute(pendingReq, executionContext, request, response); + } else { + throw new IllegalStateException("Task needs to be executed within a Spring web environment."); + } + } + + /** + * Executes the task providing the underlying {@link ExecutionContext} {@code executionContext} as + * well as the respective {@link HttpServletRequest} and {@link HttpServletResponse}. + * + * @param executionContext The execution context (never {@code null}). + * @param request The HttpServletRequest (never {@code null}). + * @param response The HttpServletResponse (never {@code null}). + * @throws IllegalStateException Thrown in case the task is nur being run within the required + * environment. Refer to javadoc for further information. + * @throws Exception Thrown in case of error executing the task. + */ + public abstract void execute(ExecutionContext executionContext, HttpServletRequest request, + HttpServletResponse response) throws TaskExecutionException; + + /** + * Executes the task providing the underlying {@link ExecutionContext} {@code executionContext} + * and the {@link IRequest} {@code pendingReq }as well as the respective + * {@link HttpServletRequest} and {@link HttpServletResponse}. + * + * <p> + * This method sets the pending-request object of the task implementation and starts the + * {@code execute} method of the task + * </p> + * + * @param pendingReq The pending-request object (never {@code null}). + * @param executionContext The execution context (never {@code null}). + * @param request The HttpServletRequest (never {@code null}). + * @param response The HttpServletResponse (never {@code null}). + * @return The pending-request object, because Process-management works recursive + * + * @throws IllegalStateException Thrown in case the task is being run within the required + * environment. Refer to javadoc for further information. + * @throws Exception Thrown in case of error executing the task. + */ + protected abstract IRequest internalExecute(IRequest pendingReq, + ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException; + - /** - * Executes the task providing the underlying {@link ExecutionContext} {@code executionContext} - * and the {@link IRequest} {@code pendingReq }as well as the - * respective {@link HttpServletRequest} and {@link HttpServletResponse}. - * - * This method sets the pending-request object of the task implementation and starts the - * {@code execute} method of the task - * - * @param pendingReq The pending-request object (never {@code null}). - * @param executionContext The execution context (never {@code null}). - * @param request The HttpServletRequest (never {@code null}). - * @param response The HttpServletResponse (never {@code null}). - * @return The pending-request object, because Process-management works recursive - * - * @throws IllegalStateException - * Thrown in case the task is being run within the required environment. Refer to javadoc for - * further information. - * @throws Exception - * Thrown in case of error executing the task. - */ - protected abstract IRequest internalExecute(IRequest pendingReq, ExecutionContext executionContext, HttpServletRequest request, - HttpServletResponse response) throws TaskExecutionException; - - @Override - public IRequest execute(IRequest pendingReq, ExecutionContext executionContext) throws TaskExecutionException { - RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); - if (requestAttributes != null && requestAttributes instanceof ServletRequestAttributes) { - HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); - HttpServletResponse response = ((ServletRequestAttributes) requestAttributes).getResponse(); - if (request == null || response == null) { - throw new IllegalStateException( - "Spring's RequestContextHolder did not provide HttpServletResponse. Did you forget to set the required org.springframework.web.filter.RequestContextFilter in your web.xml."); - } - return internalExecute(pendingReq, executionContext, request, response); - } else { - throw new IllegalStateException("Task needs to be executed within a Spring web environment."); - } - } } diff --git a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/SpringWebExpressionEvaluator.java b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/SpringWebExpressionEvaluator.java index 5ebc1b58..c723a728 100644 --- a/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/SpringWebExpressionEvaluator.java +++ b/eaaf_core/src/main/java/at/gv/egiz/eaaf/core/impl/idp/process/springweb/SpringWebExpressionEvaluator.java @@ -1,43 +1,33 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.core.impl.idp.process.springweb; import java.io.Serializable; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import java.util.Map.Entry; import java.util.Objects; - import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; - -import org.apache.commons.lang3.ArrayUtils; +import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; +import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext; +import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluator; +import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition; import org.apache.commons.lang3.BooleanUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -49,121 +39,89 @@ import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; -import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; -import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluationContext; -import at.gv.egiz.eaaf.core.api.idp.process.ExpressionEvaluator; -import at.gv.egiz.eaaf.core.impl.idp.process.model.Transition; - /** - * Expression evaluator for processing {@link Transition} conditions allowing to + * Expression evaluator for processing {@link Transition} conditions allowing to. * <ul> * <li>reference Spring beans from the application context using {@code @myBeanName...},</li> * <li>{@link ExecutionContext} properties using {@code ctx['property']},</li> - * <li>Multi valued {@link HttpServletRequest} parameters using {@code requestParameters['foo']} (keep in mind that this - * expression returns an array of String values) and</li> - * <li>Single valued {@link HttpServletRequest} parameters using {@code requestParameter['foo']}</li> + * <li>Multi valued {@link HttpServletRequest} parameters using {@code requestParameters['foo']} + * (keep in mind that this expression returns an array of String values) and</li> + * <li>Single valued {@link HttpServletRequest} parameters using + * {@code requestParameter['foo']}</li> * </ul> - * + * * @author tknall - * + * */ public class SpringWebExpressionEvaluator implements ExpressionEvaluator { - private Logger log = LoggerFactory.getLogger(getClass()); - private ExpressionParser parser = new SpelExpressionParser(); - private StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); - - @Autowired(required = false) - private ApplicationContext ctx; - - @Autowired(required = false) - private HttpServletRequest request; - - @PostConstruct - private void init() { - if (ctx != null) { - evaluationContext.setBeanResolver(new BeanFactoryResolver(ctx)); - } - } - - /** - * Evaluation context that provides access to {@link HttpServletRequest} parameters using - * {@code requestParameter['foo']} for single value parameters or {@code requestParameters['foo']} for multi value - * parameters. Basic calls to {@code ctx} will be delegated. - * - * @author tknall - * - */ - private class SpringWebExpressionEvaluationContext implements ExpressionEvaluationContext { - - private static final long serialVersionUID = 1L; - - /** - * Creates a new expression evaluation context, providing access to HttpServletRequest parameter(s). - * - * @param delegate - * The original {@link ExpressionEvaluationContext} to be delegated to for {@code ctx['foo']} - * expressions. - */ - public SpringWebExpressionEvaluationContext(ExpressionEvaluationContext delegate) { - this.delegate = delegate; - } - - private ExpressionEvaluationContext delegate; - - @Override - public Map<String, Serializable> getCtx() { - return delegate.getCtx(); - } - - @SuppressWarnings("unused") - public Map<String, String> getRequestParameter() { - if (request != null) { - Map<String, String> singleValueMap = new HashMap<String, String>(); - Iterator<Entry<String, String[]>> it = request.getParameterMap().entrySet().iterator(); - while (it.hasNext()) { - Entry<String, String[]> entry = it.next(); - if (ArrayUtils.isNotEmpty(entry.getValue())) { - singleValueMap.put(entry.getKey(), entry.getValue()[0]); - } - } - return singleValueMap; - } else { - return Collections.<String, String> emptyMap(); - } - } - - @SuppressWarnings("unused") - public Map<String, String[]> getRequestParameters() { - if (request != null) { - return request.getParameterMap(); - } else { - return Collections.<String, String[]> emptyMap(); - } - } - - } - - @Override - public boolean evaluate(ExpressionEvaluationContext expressionContext, String expression) { - Objects.requireNonNull(expression, "Expression must not be null."); - log.trace("Evaluating '{}'.", expression); - - Expression expr = parser.parseExpression(expression); - Boolean result = null; - try { - result = expr.getValue(evaluationContext, new SpringWebExpressionEvaluationContext(expressionContext), - Boolean.class); - if (result == null) { - log.debug("Evaluation of '{}' results in null-value.", expression); - } else { - log.debug("Expression '{}' -> {}", expression, result); - } - } catch (Exception e) { - log.warn("Expression '{}' could not be processed.", expression, e); - } - - return BooleanUtils.isTrue(result); - } + private final Logger log = LoggerFactory.getLogger(getClass()); + private final ExpressionParser parser = new SpelExpressionParser(); + private final StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + + @Autowired(required = false) + private ApplicationContext ctx; + + @PostConstruct + private void init() { + if (ctx != null) { + evaluationContext.setBeanResolver(new BeanFactoryResolver(ctx)); + } + } + + /** + * Evaluation context that provides access to {@link HttpServletRequest} parameters using + * {@code requestParameter['foo']} for single value parameters or {@code requestParameters['foo']} + * for multi value parameters. Basic calls to {@code ctx} will be delegated. + * + * @author tknall + * + */ + private static class SpringWebExpressionEvaluationContext implements ExpressionEvaluationContext { + + private static final long serialVersionUID = 1L; + + /** + * Creates a new expression evaluation context, providing access to HttpServletRequest + * parameter(s). + * + * @param delegate The original {@link ExpressionEvaluationContext} to be delegated to for + * {@code ctx['foo']} expressions. + */ + public SpringWebExpressionEvaluationContext(final ExpressionEvaluationContext delegate) { + this.delegate = delegate; + } + + private final ExpressionEvaluationContext delegate; + + @Override + public Map<String, Serializable> getCtx() { + return delegate.getCtx(); + } + + } + + @Override + public boolean evaluate(final ExpressionEvaluationContext expressionContext, + final String expression) { + Objects.requireNonNull(expression, "Expression must not be null."); + log.trace("Evaluating '{}'.", expression); + + final Expression expr = parser.parseExpression(expression); + Boolean result = null; + try { + result = expr.getValue(evaluationContext, + new SpringWebExpressionEvaluationContext(expressionContext), Boolean.class); + if (result == null) { + log.debug("Evaluation of '{}' results in null-value.", expression); + } else { + log.debug("Expression '{}' -> {}", expression, result); + } + } catch (final Exception e) { + log.warn("Expression '{}' could not be processed.", expression, e); + } + + return BooleanUtils.isTrue(result); + } } |