├── .gitignore ├── telekom-workflow-api ├── .gitignore ├── README.md └── src │ └── main │ └── java │ └── ee │ └── telekom │ └── workflow │ ├── api │ ├── DslMainBlock.java │ ├── DslElseBlock.java │ ├── DslWhileDoBlock.java │ ├── WorkflowFactory.java │ ├── AutoRecovery.java │ ├── DslDoWhileBlock.java │ ├── DslAttribute.java │ ├── DslSplit.java │ ├── DslIfBlock.java │ ├── DslVariable.java │ └── DslBranchBlock.java │ ├── listener │ ├── WorkflowInstanceEventListener.java │ ├── HumanTaskEventListener.java │ ├── WorkflowInstanceEvent.java │ └── HumanTaskEvent.java │ └── facade │ └── model │ ├── WorkflowInstanceFacadeStatus.java │ ├── CreateWorkflowInstance.java │ └── ExecutionErrorState.java ├── telekom-workflow-engine ├── .gitignore ├── src │ ├── test │ │ ├── resources │ │ │ ├── logging.properties │ │ │ ├── logback-test.xml │ │ │ ├── testApplicationContext-full.xml │ │ │ ├── testApplicationContext.xml │ │ │ └── application.properties │ │ └── java │ │ │ └── ee │ │ │ └── telekom │ │ │ └── workflow │ │ │ ├── util │ │ │ └── json │ │ │ │ └── TestEnum.java │ │ │ ├── TestApplicationContexts.java │ │ │ ├── FullApplicationContextIT.java │ │ │ ├── graph │ │ │ ├── node │ │ │ │ └── gateway │ │ │ │ │ ├── _01_SequenceTest.java │ │ │ │ │ ├── _02_ParallelSplitTest.java │ │ │ │ │ ├── _05_SimpleMergeTest.java │ │ │ │ │ ├── _06_MultipleChoiceTest.java │ │ │ │ │ └── _03_SynchronizationTest.java │ │ │ ├── SimpleCounter.java │ │ │ ├── core │ │ │ │ ├── GraphRepositoryTest.java │ │ │ │ ├── GraphValidatorTest.java │ │ │ │ └── AbortInstanceTest.java │ │ │ └── RecordPathScript.java │ │ │ └── executor │ │ │ └── lifeycle │ │ │ └── MockLifecycleService.java │ └── main │ │ ├── scripts │ │ └── create_database_ENGINE.sql │ │ ├── java │ │ └── ee │ │ │ └── telekom │ │ │ └── workflow │ │ │ ├── core │ │ │ ├── workitem │ │ │ │ ├── WorkItemType.java │ │ │ │ ├── WorkItemService.java │ │ │ │ └── WorkItemRowMapper.java │ │ │ ├── notification │ │ │ │ └── ExceptionNotificationService.java │ │ │ ├── workflowinstance │ │ │ │ ├── WorkflowInstanceStatus.java │ │ │ │ └── WorkflowInstanceRowMapper.java │ │ │ ├── workunit │ │ │ │ ├── WorkType.java │ │ │ │ ├── WorkUnitService.java │ │ │ │ └── WorkUnitRowMapper.java │ │ │ ├── retry │ │ │ │ ├── RetryService.java │ │ │ │ └── RetryServiceImpl.java │ │ │ ├── archive │ │ │ │ ├── ArchiveService.java │ │ │ │ └── ArchiveServiceImpl.java │ │ │ ├── error │ │ │ │ ├── ExecutionErrorService.java │ │ │ │ ├── ExecutionErrorRowMapper.java │ │ │ │ ├── ExecutionErrorServiceImpl.java │ │ │ │ ├── ExecutionError.java │ │ │ │ └── ExecutionErrorDao.java │ │ │ ├── node │ │ │ │ ├── NodeService.java │ │ │ │ ├── NodeRowMapper.java │ │ │ │ ├── NodeStatus.java │ │ │ │ └── Node.java │ │ │ ├── abort │ │ │ │ └── AbortService.java │ │ │ ├── recovery │ │ │ │ ├── RecoveryService.java │ │ │ │ └── RecoveryServiceImpl.java │ │ │ └── common │ │ │ │ └── UnexpectedStatusException.java │ │ │ ├── graph │ │ │ ├── BeanResolver.java │ │ │ ├── WorkItemStatus.java │ │ │ ├── node │ │ │ │ ├── expression │ │ │ │ │ └── Expression.java │ │ │ │ ├── output │ │ │ │ │ ├── OutputMapping.java │ │ │ │ │ ├── ValueMapping.java │ │ │ │ │ └── MapEntryMapping.java │ │ │ │ ├── input │ │ │ │ │ ├── InputMapping.java │ │ │ │ │ ├── ConstantMapping.java │ │ │ │ │ ├── DueDateMapping.java │ │ │ │ │ ├── AttributeMapping.java │ │ │ │ │ ├── ArrayMapping.java │ │ │ │ │ ├── MapMapping.java │ │ │ │ │ ├── ExpressionLanguageMapping.java │ │ │ │ │ └── ExpressionMapping.java │ │ │ │ ├── gateway │ │ │ │ │ ├── condition │ │ │ │ │ │ ├── Condition.java │ │ │ │ │ │ ├── AttributeEqualsCondition.java │ │ │ │ │ │ └── ExpressionLanguageCondition.java │ │ │ │ │ ├── AbstractGateway.java │ │ │ │ │ ├── XorJoin.java │ │ │ │ │ ├── AbstractConditionalGateway.java │ │ │ │ │ ├── CancellingDiscriminator.java │ │ │ │ │ └── AndJoin.java │ │ │ │ ├── AbstractNode.java │ │ │ │ ├── activity │ │ │ │ │ └── ScriptActivity.java │ │ │ │ └── event │ │ │ │ │ └── ThrowEscalation.java │ │ │ ├── WorkflowException.java │ │ │ ├── NewGraphInstanceCreator.java │ │ │ ├── el │ │ │ │ ├── ReservedVariables.java │ │ │ │ └── EnvironmentBeanNameResolver.java │ │ │ ├── core │ │ │ │ ├── MapBeanResolver.java │ │ │ │ ├── TransitionImpl.java │ │ │ │ └── TokenImpl.java │ │ │ ├── GraphValidator.java │ │ │ ├── NodeEventListener.java │ │ │ ├── GraphWorkItemEventListener.java │ │ │ ├── Transition.java │ │ │ ├── GraphInstanceEventListener.java │ │ │ ├── GraphWorkItem.java │ │ │ ├── GraphRepository.java │ │ │ └── Token.java │ │ │ ├── util │ │ │ ├── NoStackTraceException.java │ │ │ ├── YesNoUtil.java │ │ │ ├── ExecutorServiceUtil.java │ │ │ ├── AbstractDao.java │ │ │ ├── ExceptionUtil.java │ │ │ ├── NamedPoolThreadFactory.java │ │ │ ├── SimpleLifeCycleBean.java │ │ │ ├── AbstractWorkflowEngineDao.java │ │ │ ├── StatisticsLoggingAspect.java │ │ │ └── CallUtil.java │ │ │ ├── executor │ │ │ ├── WorkflowExecutor.java │ │ │ ├── consumer │ │ │ │ ├── WorkConsumerService.java │ │ │ │ └── WorkConsumerJob.java │ │ │ ├── queue │ │ │ │ └── WorkQueue.java │ │ │ ├── lifecycle │ │ │ │ ├── HealthCheckService.java │ │ │ │ └── LifecycleService.java │ │ │ ├── producer │ │ │ │ ├── WorkProducerService.java │ │ │ │ ├── WorkProducerJob.java │ │ │ │ └── WorkProducerServiceImpl.java │ │ │ └── marshall │ │ │ │ ├── TokenState.java │ │ │ │ └── GraphInstanceRepository.java │ │ │ ├── facade │ │ │ ├── util │ │ │ │ ├── SqlUtil.java │ │ │ │ └── DateUtil.java │ │ │ ├── workflowinstance │ │ │ │ ├── WorkflowStatusCountRowMapper.java │ │ │ │ ├── WorkflowStatusCount.java │ │ │ │ ├── WorkflowInstancesDataTableColumnMapper.java │ │ │ │ └── WorkflowInstanceStateRowMapper.java │ │ │ └── workitem │ │ │ │ └── WorkItemStateRowMapper.java │ │ │ └── jmx │ │ │ └── EngineMonitor.java │ │ └── resources │ │ ├── workflow-engine-aop.xml │ │ ├── workflow-engine-components.xml │ │ ├── workflow-engine-configuration.xml │ │ ├── workflow-engine-jta.xml │ │ └── workflow-engine-jmx.xml └── README.md ├── telekom-workflow-test ├── .gitignore ├── README.md └── src │ └── main │ └── java │ └── ee │ └── telekom │ └── workflow │ └── test │ └── TestGraphEngineFactory.java ├── telekom-workflow-web ├── .gitignore ├── src │ ├── main │ │ ├── resources │ │ │ ├── META-INF │ │ │ │ ├── resources │ │ │ │ │ └── WEB-INF │ │ │ │ │ │ ├── images │ │ │ │ │ │ ├── icos.png │ │ │ │ │ │ ├── logo.png │ │ │ │ │ │ ├── bg-sort.png │ │ │ │ │ │ ├── favicon.ico │ │ │ │ │ │ ├── ico-info.png │ │ │ │ │ │ ├── bg-buttons.png │ │ │ │ │ │ ├── bg-select.png │ │ │ │ │ │ ├── ico-check.png │ │ │ │ │ │ ├── ico-error.png │ │ │ │ │ │ ├── bg-gradient.png │ │ │ │ │ │ ├── ico-filetypes.png │ │ │ │ │ │ ├── ico-info-big.png │ │ │ │ │ │ ├── bg-check-radio.png │ │ │ │ │ │ ├── ico-close-small.png │ │ │ │ │ │ ├── ico-datepicker.png │ │ │ │ │ │ └── bg-buttons-round.png │ │ │ │ │ │ └── jsp-twe │ │ │ │ │ │ ├── footer.jspf │ │ │ │ │ │ ├── error.jsp │ │ │ │ │ │ ├── init.jspf │ │ │ │ │ │ └── console │ │ │ │ │ │ ├── status.jsp │ │ │ │ │ │ └── workflow │ │ │ │ │ │ └── item.jsp │ │ │ │ ├── tags │ │ │ │ │ ├── adminAccess.tag │ │ │ │ │ └── menu.tag │ │ │ │ └── telekom-workflow-ui.tld │ │ │ └── workflow-engine-application-context.xml │ │ └── java │ │ │ └── ee │ │ │ └── telekom │ │ │ └── workflow │ │ │ └── web │ │ │ ├── rest │ │ │ ├── form │ │ │ │ └── UpdateInstanceStatusForm.java │ │ │ └── model │ │ │ │ ├── WorkflowInstanceRestModel.java │ │ │ │ └── HumanTaskModel.java │ │ │ ├── console │ │ │ ├── form │ │ │ │ ├── ExecuteWorkItemForm.java │ │ │ │ ├── BatchCreateWorkflowInstancesForm.java │ │ │ │ ├── SearchWorkflowInstancesForm.java │ │ │ │ └── CreateWorkflowInstanceForm.java │ │ │ ├── model │ │ │ │ ├── MbeanAttributeModel.java │ │ │ │ ├── DataTable.java │ │ │ │ └── WorkItemStateModel.java │ │ │ ├── WorkflowDefinitionsController.java │ │ │ └── helper │ │ │ │ └── MessageHelper.java │ │ │ ├── LoggingHandlerExceptionResolver.java │ │ │ ├── util │ │ │ ├── LogbackStopListener.java │ │ │ ├── JsonParserUtil.java │ │ │ └── JdbcDriverDeregisterListener.java │ │ │ └── IndexController.java │ └── test │ │ └── java │ │ └── ee │ │ └── telekom │ │ └── workflow │ │ └── web │ │ └── console │ │ └── form │ │ └── SearchWorkflowInstancesFormTest.java └── README.md ├── telekom-workflow-example ├── src │ ├── main │ │ ├── webapp │ │ │ ├── images │ │ │ │ └── logo.png │ │ │ └── WEB-INF │ │ │ │ └── application-context.xml │ │ ├── resources │ │ │ ├── example-plugin-context.xml │ │ │ └── logback.xml │ │ └── java │ │ │ └── ee │ │ │ └── telekom │ │ │ └── workflow │ │ │ └── example │ │ │ ├── definition │ │ │ ├── ExampleStepSelector.java │ │ │ └── Example_00_StepSelection.java │ │ │ ├── security │ │ │ └── DummyAuthenticationProvider.java │ │ │ └── service │ │ │ └── CustomerService.java │ └── test │ │ └── java │ │ └── ee │ │ └── telekom │ │ └── workflow │ │ └── example │ │ └── definition │ │ └── ExampleStep00Test.java ├── .gitignore ├── conf │ └── default │ │ ├── default.properties │ │ └── server.xml ├── README.md └── build.cmd └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings/ 5 | target/ 6 | .DS_Store 7 | 8 | # IntelliJ 9 | *.iml 10 | .idea 11 | -------------------------------------------------------------------------------- /telekom-workflow-api/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings/ 5 | target/ 6 | .DS_Store 7 | 8 | # IntelliJ 9 | *.iml 10 | -------------------------------------------------------------------------------- /telekom-workflow-engine/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings/ 5 | target/ 6 | .DS_Store 7 | 8 | # IntelliJ 9 | *.iml 10 | -------------------------------------------------------------------------------- /telekom-workflow-test/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings/ 5 | target/ 6 | .DS_Store 7 | 8 | # IntelliJ 9 | *.iml 10 | -------------------------------------------------------------------------------- /telekom-workflow-web/.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings/ 5 | target/ 6 | .DS_Store 7 | 8 | # IntelliJ 9 | *.iml 10 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/resources/logging.properties: -------------------------------------------------------------------------------- 1 | handlers = org.slf4j.bridge.SLF4JBridgeHandler 2 | .handlers = org.slf4j.bridge.SLF4JBridgeHandler -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/util/json/TestEnum.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util.json; 2 | 3 | public enum TestEnum { 4 | ONE, TWO 5 | } 6 | -------------------------------------------------------------------------------- /telekom-workflow-example/src/main/webapp/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-example/src/main/webapp/images/logo.png -------------------------------------------------------------------------------- /telekom-workflow-example/.gitignore: -------------------------------------------------------------------------------- 1 | conf/profile.properties 2 | 3 | # Eclipse 4 | .classpath 5 | .project 6 | .settings/ 7 | target/ 8 | runtime/ 9 | .DS_Store 10 | 11 | # IntelliJ 12 | *.iml 13 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/icos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/icos.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/logo.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-sort.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-sort.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/favicon.ico -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-info.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-buttons.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-select.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-check.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-error.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-gradient.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-filetypes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-filetypes.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-info-big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-info-big.png -------------------------------------------------------------------------------- /telekom-workflow-test/README.md: -------------------------------------------------------------------------------- 1 | telekom-workflow-test 2 | ======================= 3 | 4 | This project provides helper classes for building automated tests for your workflow definitions. 5 | 6 | Detailed documentation can be found from the wiki: TODO -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-check-radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-check-radio.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-close-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-close-small.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-datepicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/ico-datepicker.png -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/tags/adminAccess.tag: -------------------------------------------------------------------------------- 1 | <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-buttons-round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zutnop/telekom-workflow-engine/HEAD/telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/images/bg-buttons-round.png -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/scripts/create_database_ENGINE.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE workflowengine; 2 | 3 | CREATE USER engine WITH PASSWORD 'engine'; 4 | GRANT ALL PRIVILEGES ON DATABASE workflowengine TO engine; 5 | 6 | CREATE SCHEMA engine AUTHORIZATION engine; -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/workitem/WorkItemType.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.workitem; 2 | 3 | public enum WorkItemType{ 4 | 5 | SIGNAL, 6 | 7 | TIMER, 8 | 9 | TASK, 10 | 11 | HUMAN_TASK 12 | 13 | } 14 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/notification/ExceptionNotificationService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.notification; 2 | 3 | public interface ExceptionNotificationService{ 4 | 5 | void handleException( Exception exception ); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /telekom-workflow-web/README.md: -------------------------------------------------------------------------------- 1 | telekom-workflow-web 2 | ======================= 3 | 4 | This project will provide a management console and the REST API for the workflow engine. 5 | 6 | Detailed documentation can be found from the wiki: https://github.com/zutnop/telekom-workflow-engine/wiki/Engine-web-console -------------------------------------------------------------------------------- /telekom-workflow-api/README.md: -------------------------------------------------------------------------------- 1 | telekom-workflow-api 2 | ======================= 3 | 4 | This project provides an API for writing workflow definitions, event listeners and interacting with the workflow engine. 5 | 6 | Detailed documentation can be found from the wiki: https://github.com/zutnop/telekom-workflow-engine/wiki/Workflow-development-guide -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/TestApplicationContexts.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow; 2 | 3 | 4 | public class TestApplicationContexts{ 5 | 6 | public static final String DEFAULT = "/testApplicationContext.xml"; 7 | public static final String FULL = "/testApplicationContext-full.xml"; 8 | 9 | } 10 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/BeanResolver.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | /** 4 | * A bean resolve resolves a bean object based on a bean name. A bean resolver may be used by some node types. 5 | */ 6 | public interface BeanResolver{ 7 | 8 | Object getBean( String name ); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/jsp-twe/footer.jspf: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> 2 | 3 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/WorkItemStatus.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | public enum WorkItemStatus { 4 | 5 | NEW, 6 | 7 | EXECUTING, 8 | 9 | EXECUTED, 10 | 11 | EXECUTING_ERROR, 12 | 13 | COMPLETING, 14 | 15 | COMPLETED, 16 | 17 | COMPLETING_ERROR, 18 | 19 | CANCELLED; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/expression/Expression.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.expression; 2 | 3 | /** 4 | * Interface for an expression that can be executed with optional arguments and may return a value. 5 | */ 6 | public interface Expression { 7 | 8 | T execute( Object... arguments ); 9 | 10 | } 11 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/NoStackTraceException.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | public class NoStackTraceException extends Exception{ 4 | 5 | private static final long serialVersionUID = 1L; 6 | 7 | public NoStackTraceException( String message ){ 8 | super( message, null, true, false ); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /telekom-workflow-engine/README.md: -------------------------------------------------------------------------------- 1 | telekom-workflow-engine 2 | ======================= 3 | 4 | This project provides the workflow engine itself. 5 | 6 | Detailed documentation can be found from the wiki: 7 | https://github.com/zutnop/telekom-workflow-engine/wiki/Engine-concepts 8 | https://github.com/zutnop/telekom-workflow-engine/wiki/Engine-architecture 9 | https://github.com/zutnop/telekom-workflow-engine/wiki/Engine-development-guide -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/workflowinstance/WorkflowInstanceStatus.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.workflowinstance; 2 | 3 | public enum WorkflowInstanceStatus { 4 | 5 | NEW, 6 | 7 | STARTING, 8 | 9 | EXECUTING, 10 | 11 | EXECUTED, 12 | 13 | SUSPENDED, 14 | 15 | ABORT, 16 | 17 | ABORTING, 18 | 19 | ABORTED, 20 | 21 | STARTING_ERROR, 22 | 23 | EXECUTING_ERROR, 24 | 25 | ABORTING_ERROR 26 | 27 | } 28 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/rest/form/UpdateInstanceStatusForm.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.rest.form; 2 | 3 | public class UpdateInstanceStatusForm{ 4 | private String status; 5 | 6 | public UpdateInstanceStatusForm(){ 7 | } 8 | 9 | public UpdateInstanceStatusForm( String status ){ 10 | this.status = status; 11 | } 12 | 13 | public String getStatus(){ 14 | return status; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/DslMainBlock.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface DslMainBlock extends DslBlock>{ 12 | 13 | /** 14 | * Must be called once as the last method on the factory. 15 | */ 16 | void end(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /telekom-workflow-example/conf/default/default.properties: -------------------------------------------------------------------------------- 1 | memory.options=-Xms512m -Xmx512m 2 | tomcat.shutdown.port=8007 3 | tomcat.http.port=9999 4 | tomcat.version=10.1.36 5 | tomcat.cleanSessionsOnStartup=true 6 | 7 | jpda.enabled=true 8 | jpda.port=8002 9 | jpda.params=-agentlib:jdwp=transport=dt_socket,address=${jpda.port},server=y,suspend=n 10 | 11 | jrebel.enabled=false 12 | jrebel.params=-Drebel.workspace.path="C:\\projects\\telekom-workflow-engine" -javaagent:"C:\\java\\jrebel\\jrebel.jar" 13 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/DslElseBlock.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface DslElseBlock extends DslBlock>{ 12 | 13 | /** 14 | * Block end tag, closes the previously started if-elseIf-else-endIf block. 15 | */ 16 | Level endIf(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/DslWhileDoBlock.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface DslWhileDoBlock extends DslBlock>{ 12 | 13 | /** 14 | * Block end tag, closes the previously started whileDo block. 15 | */ 16 | Level whileDo(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/workunit/WorkType.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.workunit; 2 | 3 | public enum WorkType{ 4 | 5 | START_WORKFLOW("s"), 6 | 7 | ABORT_WORKFLOW("a"), 8 | 9 | COMPLETE_WORK_ITEM("c"), 10 | 11 | EXECUTE_TASK("e"); 12 | 13 | private String code; 14 | 15 | WorkType( String code ){ 16 | this.code = code; 17 | } 18 | 19 | public String getCode(){ 20 | return code; 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/WorkflowFactory.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface WorkflowFactory{ 12 | 13 | /** 14 | * Must be called once as the first method on the factory. Initiates the main branch starting point. 15 | */ 16 | DslValidationBlock start(); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/WorkflowException.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | /** 4 | * Generic exception class for workflow execution errors 5 | */ 6 | public class WorkflowException extends RuntimeException { 7 | 8 | private static final long serialVersionUID = 1L; 9 | 10 | public WorkflowException(String message) { 11 | super(message); 12 | } 13 | 14 | public WorkflowException(String message, Throwable cause) { 15 | super(message, cause); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/NewGraphInstanceCreator.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | import ee.telekom.workflow.graph.node.activity.CreateNewInstanceActivity; 4 | 5 | /** 6 | * Creates a new instance as defined by the arguments. Used to create instances for {@link CreateNewInstanceActivity} 7 | */ 8 | public interface NewGraphInstanceCreator{ 9 | 10 | void create( String graphName, Integer graphVersion, String label1, String label2, Environment initialEnvironment ); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/console/form/ExecuteWorkItemForm.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console.form; 2 | 3 | import java.io.Serializable; 4 | 5 | public class ExecuteWorkItemForm implements Serializable { 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | private String result; 10 | 11 | public String getResult(){ 12 | return result; 13 | } 14 | 15 | public void setResult( String result ){ 16 | this.result = result; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/WorkflowExecutor.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor; 2 | 3 | /** 4 | * Provides the execution logic for the 4 work unit types. 5 | * 6 | * @author Christian Klock 7 | */ 8 | public interface WorkflowExecutor{ 9 | 10 | void startWorkflow( long woinRefNum ); 11 | 12 | void abortWorkflow( long woinRefNum ); 13 | 14 | void completeWorkItem( long woinRefNum, long woitRefNum ); 15 | 16 | void executeTask( long woinRefNum, long woitRefNum ); 17 | 18 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/output/OutputMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.output; 2 | 3 | import ee.telekom.workflow.graph.Environment; 4 | import ee.telekom.workflow.graph.GraphInstance; 5 | 6 | /** 7 | * An OutputMapping describes how the execution result of a node is mapped into the {@link Environment} 8 | * of the {@link GraphInstance} being executed. 9 | */ 10 | public interface OutputMapping{ 11 | 12 | void map( Environment environment, Object result ); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/retry/RetryService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.retry; 2 | 3 | public interface RetryService{ 4 | 5 | /** 6 | * If the execution of a workflow (starting or aborting it, executing a task or completing a work item) 7 | * fails, then the error is stored in the database and the instance remains locked. 8 | * 9 | * This method prepare the workflow instance for retrying the failed excecution. 10 | */ 11 | void retry( long woinRefNum ); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/jsp-twe/error.jsp: -------------------------------------------------------------------------------- 1 | <%@ page isErrorPage="true" language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> 2 | <%@ include file="header.jspf" %> 3 | 4 |

An exception occured:

5 | 6 |
 7 | Message:
 8 | <%=exception.getMessage()%>
 9 | 
10 | StackTrace:
11 | 
12 | 
13 |

14 | 15 | <%@ include file="footer.jspf" %> -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/AutoRecovery.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * Enum indicating if work item is automatically retried on recovery. 5 | */ 6 | public enum AutoRecovery { 7 | ENABLED, DISABLED; 8 | 9 | public static AutoRecovery of(boolean autoRecovery){ 10 | return autoRecovery ? ENABLED : DISABLED; 11 | } 12 | 13 | public static AutoRecovery getDefault(){ 14 | return ENABLED; 15 | } 16 | 17 | public boolean asBoolean(){ 18 | return this == ENABLED; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/input/InputMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.input; 2 | 3 | import ee.telekom.workflow.graph.Environment; 4 | import ee.telekom.workflow.graph.GraphInstance; 5 | 6 | /** 7 | * An InputMapping describes an input parameter to a node execution. The value of this parameter is evaluated dynamically 8 | * and may depend on the {@link Environment} of the {@link GraphInstance} being executed. 9 | */ 10 | public interface InputMapping { 11 | 12 | T evaluate( GraphInstance instance ); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/el/ReservedVariables.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.el; 2 | 3 | /** 4 | * This interface lists the reserved variable names that have a special handling (as oppose to resolving from Environment) when evaluating an EL expression. 5 | * 6 | * @author Erko Hansar 7 | */ 8 | public interface ReservedVariables{ 9 | 10 | // evaluates to current Date 11 | String NOW = "NOW"; 12 | 13 | // evaluates to current workflow instance id (ref_num) value 14 | String WORKFLOW_INSTANCE_ID = "WORKFLOW_INSTANCE_ID"; 15 | 16 | } 17 | -------------------------------------------------------------------------------- /telekom-workflow-example/README.md: -------------------------------------------------------------------------------- 1 | telekom-workflow-example 2 | ======================= 3 | 4 | This project will provide an example implementing application for the workflow engine. 5 | 6 | 1. Copy conf/default/default.properties to conf/profile.properties and overwrite your desired configuration parameters. 7 | 2. Build the modules. 8 | 3. Run 'ant setup' once. 9 | 4. Then run 'ant start' and 'ant stop' to start and stop the embedded tomcat server with the example project. 10 | 11 | Detailed documentation can be found from the wiki: https://github.com/zutnop/telekom-workflow-engine/wiki/Workflow-examples -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/archive/ArchiveService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.archive; 2 | 3 | /** 4 | * Provides a method to archive a workflow instance's data once it is fully executed or aborted. 5 | * 6 | * @author Christian Klock 7 | */ 8 | public interface ArchiveService{ 9 | 10 | /** 11 | * Archive a workflow instance's data once it is fully executed or aborted. 12 | */ 13 | void archive( long woinRefNum, int archivePeriodLength ); 14 | 15 | /** 16 | * Cleans up archive entries. 17 | */ 18 | void cleanup(); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/core/MapBeanResolver.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.core; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import ee.telekom.workflow.graph.BeanResolver; 7 | 8 | public class MapBeanResolver implements BeanResolver{ 9 | 10 | private Map beans = new HashMap<>(); 11 | 12 | @Override 13 | public Object getBean( String name ){ 14 | return beans.get( name ); 15 | } 16 | 17 | public void addBean( String name, Object bean ){ 18 | beans.put( name, bean ); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /telekom-workflow-example/build.cmd: -------------------------------------------------------------------------------- 1 | cd ..\telekom-workflow-api 2 | call mvn clean install -DskipTests=true 3 | if not "%ERRORLEVEL%" == "0" exit /b 4 | 5 | cd ..\telekom-workflow-engine 6 | call mvn clean install -DskipTests=true 7 | if not "%ERRORLEVEL%" == "0" exit /b 8 | 9 | cd ..\telekom-workflow-web 10 | call mvn clean install -DskipTests=true 11 | if not "%ERRORLEVEL%" == "0" exit /b 12 | 13 | cd ..\telekom-workflow-test 14 | call mvn clean install -DskipTests=true 15 | if not "%ERRORLEVEL%" == "0" exit /b 16 | 17 | cd ..\telekom-workflow-example 18 | call mvn clean install -DskipTests=true 19 | if not "%ERRORLEVEL%" == "0" exit /b -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/FullApplicationContextIT.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.test.annotation.DirtiesContext; 6 | import org.springframework.test.context.ContextConfiguration; 7 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 8 | 9 | @RunWith(SpringJUnit4ClassRunner.class) 10 | @ContextConfiguration(locations = TestApplicationContexts.FULL) 11 | @DirtiesContext 12 | public class FullApplicationContextIT{ 13 | 14 | @Test 15 | public void test(){ 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/jsp-twe/init.jspf: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> 2 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 3 | <%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 4 | <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %> 5 | <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> 6 | <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> 7 | <%@ taglib prefix="workflow-ui" uri="http://telekom.ee/tags/workflow" %> 8 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/facade/util/SqlUtil.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class SqlUtil{ 7 | 8 | public static List> partition( List all, int partitionSize ){ 9 | List> partitions = new ArrayList<>(); 10 | final int count = all.size(); 11 | for( int i = 0; i < count; i += partitionSize ){ 12 | partitions.add( new ArrayList<>( all.subList( i, Math.min( count, i + partitionSize ) ) ) ); 13 | } 14 | return partitions; 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/GraphValidator.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Validator interface for {@link Graph}s 7 | */ 8 | public interface GraphValidator { 9 | 10 | /** 11 | * Validates the given graph and returns a list of validation errors. The 12 | * list might be empty if no errors are found but will never be 13 | * null. 14 | * 15 | * @param graph 16 | * the graph to be validated 17 | * @return a list of validation errors or an empty list if no errors are 18 | * found 19 | */ 20 | List validate(Graph graph); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/resources/workflow-engine-aop.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/DslDoWhileBlock.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface DslDoWhileBlock extends DslBlock>{ 12 | 13 | /** 14 | * Block end tag, checks the condition result, if true, then executes the block content again, if false, then ends the block. 15 | * 16 | * @param id node id 17 | * @param condition expression language condition ("EL_EXPRESSION") 18 | */ 19 | Level doWhile( int id, String condition ); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/facade/util/DateUtil.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.util; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Date; 5 | 6 | public class DateUtil{ 7 | 8 | public static String formatDate( Date date ){ 9 | return date == null ? null : new SimpleDateFormat( "dd.MM.yyyy HH:mm:ss:SSS" ).format( date ); 10 | } 11 | 12 | public static Date min( Date date1, Date date2 ){ 13 | if( date1 == null ){ 14 | return date2; 15 | } 16 | if( date2 == null ){ 17 | return date1; 18 | } 19 | return date1.before( date2 ) ? date1 : date2; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/workunit/WorkUnitService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.workunit; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | /** 7 | * Provides services to the work unit producer part of the engine. 8 | * 9 | * @author Christian Klock 10 | */ 11 | public interface WorkUnitService{ 12 | 13 | /** 14 | * Polls new units of work from database. 15 | * 16 | * @param now the current date 17 | */ 18 | List findNewWorkUnits( Date now ); 19 | 20 | /** 21 | * Locks the workflow instances associated with the work units. 22 | */ 23 | void lock( List workUnits ); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/gateway/condition/Condition.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway.condition; 2 | 3 | import ee.telekom.workflow.graph.Environment; 4 | import ee.telekom.workflow.graph.GraphInstance; 5 | import ee.telekom.workflow.graph.node.gateway.OrFork; 6 | import ee.telekom.workflow.graph.node.gateway.XorFork; 7 | 8 | /** 9 | * Condition that is evaluated based on an {@link Environment} of a {@link GraphInstance}. Conditions are used to model the conditional execution 10 | * of subsequent branches in {@link OrFork} and {@link XorFork}s. 11 | */ 12 | public interface Condition{ 13 | 14 | boolean evaluate( GraphInstance instance ); 15 | 16 | } -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/DslAttribute.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface DslAttribute { 12 | 13 | /** 14 | * Adds an argument to the preceding node. 15 | * @param name the arguments name 16 | * @param value the arguments value (any java object or "${EL_EXPRESSION}") 17 | */ 18 | DslAttribute withAttribute( String name, Object value ); 19 | 20 | /** 21 | * Block end tag, closing the iteration of attributes. 22 | */ 23 | Level done(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/consumer/WorkConsumerService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.consumer; 2 | 3 | /** 4 | * Provides services for the workflow consumer. 5 | * 6 | * @author Christian Klock 7 | */ 8 | public interface WorkConsumerService{ 9 | 10 | /** 11 | * Consumes a single work unit. 12 | *

13 | * Blocks for 15 s or until a work unit becomes consumable, if there is currently none. 14 | * 15 | */ 16 | void consumeWorkUnit(); 17 | 18 | /** 19 | * Returns the total number of consumed work units by the engine instance at hand since 20 | * the engine's last deployment. 21 | */ 22 | long getConsumedWorkUnits(); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/node/gateway/_01_SequenceTest.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import org.junit.Test; 4 | 5 | import ee.telekom.workflow.graph.AbstractGraphTest; 6 | import ee.telekom.workflow.graph.GraphFactory; 7 | 8 | public class _01_SequenceTest extends AbstractGraphTest { 9 | 10 | @Test 11 | public void oneNode() { 12 | assertExecution(GraphFactory.INSTANCE.sequence_one(), "1"); 13 | } 14 | 15 | @Test 16 | public void twoNodes() { 17 | assertExecution(GraphFactory.INSTANCE.sequence_two(), "1,2"); 18 | } 19 | 20 | @Test 21 | public void threeNodes() { 22 | assertExecution(GraphFactory.INSTANCE.sequence_three(), "1,2,3"); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/telekom-workflow-ui.tld: -------------------------------------------------------------------------------- 1 | 2 | 7 | 1.0 8 | telekom 9 | http://telekom.ee/tags/workflow 10 | 11 | menu 12 | /META-INF/tags/menu.tag 13 | 14 | 15 | adminAccess 16 | /META-INF/tags/adminAccess.tag 17 | 18 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/DslSplit.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface DslSplit { 12 | 13 | /** 14 | * Add a branch (parallel execution flow) into the active split. 15 | */ 16 | DslBranchBlock branch(); 17 | 18 | /** 19 | * Add a conditional branch (parallel execution flow) into the active split. Executed only if the condition evaluates to true. 20 | * 21 | * @param condition expression language condition ("EL_EXPRESSION") 22 | */ 23 | DslBranchBlock branch( String condition ); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/archive/ArchiveServiceImpl.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.archive; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Service; 5 | import org.springframework.transaction.annotation.Transactional; 6 | 7 | @Service 8 | @Transactional 9 | public class ArchiveServiceImpl implements ArchiveService{ 10 | 11 | @Autowired 12 | private ArchiveDao archiveDao; 13 | 14 | @Override 15 | public void archive( long woinRefNum, int archivePeriodLength ){ 16 | archiveDao.archive( woinRefNum, archivePeriodLength ); 17 | } 18 | 19 | @Override 20 | public void cleanup(){ 21 | archiveDao.cleanup(); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /telekom-workflow-test/src/main/java/ee/telekom/workflow/test/TestGraphEngineFactory.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.test; 2 | 3 | import ee.telekom.workflow.core.common.WorkflowEngineConfiguration; 4 | import ee.telekom.workflow.executor.GraphEngineFactory; 5 | import ee.telekom.workflow.executor.plugin.WorkflowEnginePlugin; 6 | import ee.telekom.workflow.graph.core.GraphEngineImpl; 7 | 8 | /** 9 | * @author Raido Türk 10 | */ 11 | public class TestGraphEngineFactory extends GraphEngineFactory{ 12 | 13 | public TestGraphEngineFactory( GraphEngineImpl graphEngine, WorkflowEngineConfiguration configuration, WorkflowEnginePlugin plugin ){ 14 | singleton = graphEngine; 15 | this.configuration = configuration; 16 | this.plugin = plugin; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/workflow-engine-application-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/input/ConstantMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.input; 2 | 3 | import ee.telekom.workflow.graph.GraphInstance; 4 | 5 | /** 6 | * InputMapping of a constant value that does not depend on the environment. 7 | */ 8 | public class ConstantMapping implements InputMapping{ 9 | 10 | private T value; 11 | 12 | public ConstantMapping( T value ){ 13 | this.value = value; 14 | } 15 | 16 | public static ConstantMapping of( T value ){ 17 | return new ConstantMapping( value ); 18 | } 19 | 20 | public T getValue(){ 21 | return value; 22 | } 23 | 24 | @Override 25 | public T evaluate( GraphInstance instance ){ 26 | return value; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/queue/WorkQueue.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.queue; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | 5 | import ee.telekom.workflow.core.workunit.WorkUnit; 6 | 7 | /** 8 | * Provides a fifo queue for work units. It is part of the producer-consumer pattern for work units. 9 | * 10 | * @author Christian Klock 11 | */ 12 | public interface WorkQueue{ 13 | 14 | void start(); 15 | 16 | void stop(); 17 | 18 | boolean isStarted(); 19 | 20 | void put( WorkUnit workUnit ) throws InterruptedException; 21 | 22 | WorkUnit poll( long timeout, TimeUnit unit ) throws InterruptedException; 23 | 24 | /** 25 | * Blocks the calling thread until the queue is empty. 26 | */ 27 | void awaitEmpty(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /telekom-workflow-example/src/main/webapp/WEB-INF/application-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/error/ExecutionErrorService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.error; 2 | 3 | /** 4 | * Provides services for handling execution errors. 5 | * 6 | * @author Christian Klock 7 | */ 8 | public interface ExecutionErrorService{ 9 | 10 | /** 11 | * Creates a new {@link ExecutionError} entry. 12 | */ 13 | void handleError( long woinRefNum, Long woitRefNum, Exception exception ); 14 | 15 | /** 16 | * Returns the workflow instance's execution error or null, if the workflow 17 | * instance is currently not in an error status. 18 | */ 19 | ExecutionError findByWoinRefNum( long woinRefNum ); 20 | 21 | /** 22 | * Delete an execution error by the execution error refNum. 23 | */ 24 | void delete( long refNum ); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/YesNoUtil.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | /** 4 | * Utility class for conversion between "Y"/"N"/null and true/false/null values 5 | */ 6 | public class YesNoUtil { 7 | 8 | public static final String YES_AS_STRING = "Y"; 9 | public static final String NO_AS_STRING = "N"; 10 | 11 | /** 12 | * Converts the given flag into a string of either "Y", "N" or null. 13 | */ 14 | public static String asString(Boolean flag) { 15 | return flag == null ? null : (flag ? YES_AS_STRING : NO_AS_STRING); 16 | } 17 | 18 | /** 19 | * Converts the given string into a Boolean flag of either true, false or 20 | * null. 21 | */ 22 | public static Boolean asBoolean(String flag) { 23 | return flag == null ? null : flag.equals(YES_AS_STRING); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/ExecutorServiceUtil.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.TimeUnit; 5 | 6 | public class ExecutorServiceUtil{ 7 | 8 | public static void shutDownSynchronously( ExecutorService executorService ){ 9 | if( executorService != null ){ 10 | executorService.shutdown(); 11 | while( !executorService.isTerminated() ){ 12 | try{ 13 | executorService.awaitTermination( 1, TimeUnit.MINUTES ); 14 | } 15 | catch( InterruptedException e ){ 16 | // Do not return on interrupts, but wait until all submitted tasks are completed. 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/output/ValueMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.output; 2 | 3 | import ee.telekom.workflow.graph.Environment; 4 | 5 | /** 6 | * OutputMapping that maps the node execution result on an attribute with the given name. 7 | */ 8 | public class ValueMapping implements OutputMapping{ 9 | 10 | private String name; 11 | 12 | public ValueMapping( String name ){ 13 | this.name = name; 14 | } 15 | 16 | public static ValueMapping of( String name ){ 17 | return new ValueMapping( name ); 18 | } 19 | 20 | public String getName() { 21 | return name; 22 | } 23 | 24 | @Override 25 | public void map( Environment environment, Object result ){ 26 | environment.setAttribute( name, result ); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/consumer/WorkConsumerJob.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.consumer; 2 | 3 | import ee.telekom.workflow.executor.producer.WorkProducerJob; 4 | 5 | /** 6 | * Provides the life cycle methods of the engines work unit consumer part. 7 | *

8 | * See also {@link WorkProducerJob}. 9 | * 10 | * @author Christian Klock 11 | */ 12 | public interface WorkConsumerJob{ 13 | 14 | /** 15 | * Starts the consumers. 16 | *

17 | * Make sure you call {@link #stop()} for a clean shutdown if you called this method. 18 | * Once stopped, this method can be used to restart the consumers. 19 | */ 20 | void start(); 21 | 22 | /** 23 | * Stops the consumers. Is a no-op, if the consumers are already stopped. 24 | */ 25 | void stop(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/lifecycle/HealthCheckService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.lifecycle; 2 | 3 | /** 4 | * Service that provides logic to take appropriate actions in order to 5 | * recover persisted "broken" workflow instance and work item states after a node failure. 6 | */ 7 | public interface HealthCheckService{ 8 | 9 | /** 10 | * Called regularly to test whether there are any FAILED nodes and to take 11 | * appropriate actions to recover any potential damage by a node failure. 12 | */ 13 | void healFailedNodes(); 14 | 15 | /** 16 | * Called regularly to test whether there are any workflow instances that seem 17 | * to be stuck in the locked state and log and error to draw attention to this. 18 | */ 19 | void checkForStuckWorkflows(); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/console/form/BatchCreateWorkflowInstancesForm.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console.form; 2 | 3 | import java.io.Serializable; 4 | import java.util.List; 5 | 6 | public class BatchCreateWorkflowInstancesForm implements Serializable { 7 | 8 | private static final long serialVersionUID = 1L; 9 | 10 | private List refNums; 11 | private String batchRequest; 12 | 13 | public List getRefNums(){ 14 | return refNums; 15 | } 16 | 17 | public void setRefNums( List refNums ){ 18 | this.refNums = refNums; 19 | } 20 | 21 | public String getBatchRequest(){ 22 | return batchRequest; 23 | } 24 | 25 | public void setBatchRequest( String batchRequest ){ 26 | this.batchRequest = batchRequest; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/SimpleCounter.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | import java.util.Map; 4 | 5 | public class SimpleCounter { 6 | 7 | private int count = 0; 8 | 9 | public void inc() { 10 | ++count; 11 | } 12 | 13 | public int incAndGet() { 14 | return ++count; 15 | } 16 | 17 | public void incByDelta(int delta) { 18 | count += delta; 19 | } 20 | 21 | public int incByDeltaAndGet(int delta) { 22 | count += delta; 23 | return count; 24 | } 25 | 26 | public int get() { 27 | return count; 28 | } 29 | 30 | public void incByDeltas(int[] deltas) { 31 | for (int delta : deltas) { 32 | count += delta; 33 | } 34 | } 35 | 36 | public void add(Map deltas) { 37 | for (Map.Entry entry : deltas.entrySet()) { 38 | count += entry.getValue(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/core/GraphRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.core; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import ee.telekom.workflow.graph.AbstractGraphTest; 7 | import ee.telekom.workflow.graph.Graph; 8 | import ee.telekom.workflow.graph.GraphFactory; 9 | import ee.telekom.workflow.graph.GraphRepository; 10 | 11 | public class GraphRepositoryTest extends AbstractGraphTest{ 12 | 13 | @Test 14 | public void test_add_get(){ 15 | GraphRepository repo = new GraphRepositoryImpl(); 16 | Graph graph = GraphFactory.INSTANCE.sequence_one(); 17 | repo.addGraph( graph ); 18 | Assert.assertSame( graph, repo.getGraph( graph.getName(), graph.getVersion() ) ); 19 | Assert.assertSame( graph, repo.getGraph( graph.getName(), null ) ); 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/node/gateway/_02_ParallelSplitTest.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import org.junit.Test; 4 | 5 | import ee.telekom.workflow.graph.AbstractGraphTest; 6 | import ee.telekom.workflow.graph.GraphFactory; 7 | 8 | public class _02_ParallelSplitTest extends AbstractGraphTest { 9 | 10 | @Test 11 | public void one_branch() { 12 | assertExecution(GraphFactory.INSTANCE.split_one(), "2"); 13 | } 14 | 15 | @Test 16 | public void two_branches() { 17 | assertExecution(GraphFactory.INSTANCE.split_two(), "2,3"); 18 | } 19 | 20 | @Test 21 | public void three_branches() { 22 | assertExecution(GraphFactory.INSTANCE.split_three(), "2,3,4"); 23 | } 24 | 25 | @Test 26 | public void two_branches_with_prefix() { 27 | assertExecution(GraphFactory.INSTANCE.split_two_pre(), "1,3,4"); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/test/java/ee/telekom/workflow/web/console/form/SearchWorkflowInstancesFormTest.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console.form; 2 | 3 | import ee.telekom.workflow.facade.model.WorkflowInstanceFacadeStatus; 4 | import org.junit.*; 5 | 6 | import java.util.ArrayList; 7 | 8 | public class SearchWorkflowInstancesFormTest { 9 | 10 | @Test 11 | public void shouldRecognizeMissingSearchCriteria() { 12 | SearchWorkflowInstancesForm form = new SearchWorkflowInstancesForm(); 13 | form.setId(new ArrayList()); 14 | form.setLabel1(new ArrayList()); 15 | form.setLabel2(new ArrayList()); 16 | form.setStatus(new ArrayList()); 17 | form.setWorkflowName(new ArrayList()); 18 | form.setLength(20); 19 | form.setStart(0); 20 | Assert.assertFalse(form.hasSearchCriteria()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/node/NodeService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.node; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Interface providing services for handling cluster nodes. 7 | */ 8 | public interface NodeService{ 9 | 10 | Node findOrCreateByName( String name ); 11 | 12 | List findAllClusterNodes(); 13 | 14 | List findFailedNodes(); 15 | 16 | void updateHeartbeat( String name ); 17 | 18 | void markEnable( long refNum ); 19 | 20 | void markEnable( List nodes ); 21 | 22 | void markEnabled( long refNum ); 23 | 24 | void markDisable( long refNum ); 25 | 26 | void markDisabled( long refNum ); 27 | 28 | void markFailed( long refNum ); 29 | 30 | void markDeadNodesFailed(); 31 | 32 | void doHeartBeat(); 33 | 34 | boolean isAlive( String nodeName ); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/resources/logback-test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | %d{HH:mm:ss.SSS}||%-5level|%logger{40}|%X{workunit}|%msg|%n 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/NodeEventListener.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | /** 4 | * Listener interface for events of tokens moving through within a {@link Graph} 5 | */ 6 | public interface NodeEventListener { 7 | 8 | /** 9 | * Called before a token enters a node, i.e. before it begins executing on 10 | * the given node 11 | * 12 | * @param token 13 | * the token to enter the node 14 | * @param node 15 | * the node to be entered 16 | */ 17 | void onEntering(Token token, Node node); 18 | 19 | /** 20 | * Called after a token left a node, i.e. after the execution on the given 21 | * node completed 22 | * 23 | * @param token 24 | * the token that left the node 25 | * @param node 26 | * the node that was left 27 | */ 28 | void onLeft(Token token, Node node); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/resources/workflow-engine-components.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/gateway/AbstractGateway.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import ee.telekom.workflow.graph.Environment; 4 | import ee.telekom.workflow.graph.node.AbstractNode; 5 | 6 | /** 7 | * Abstract gateway node that implements common gateway functionality, 8 | * i.e. that gateways do not produce a return value that is to be stored 9 | * into the environment. 10 | */ 11 | public abstract class AbstractGateway extends AbstractNode{ 12 | 13 | public AbstractGateway( int id ){ 14 | super( id ); 15 | } 16 | 17 | public AbstractGateway( int id, String name ){ 18 | super( id, name ); 19 | } 20 | 21 | @Override 22 | public void store( Environment environment, Object result ){ 23 | // Gateways do not produce a result and thus do not need to store anything 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/resources/workflow-engine-configuration.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/facade/workflowinstance/WorkflowStatusCountRowMapper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.workflowinstance; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | import ee.telekom.workflow.util.AbstractRowMapper; 7 | 8 | public class WorkflowStatusCountRowMapper extends AbstractRowMapper{ 9 | 10 | public static final WorkflowStatusCountRowMapper INSTANCE = new WorkflowStatusCountRowMapper(); 11 | 12 | @Override 13 | public WorkflowStatusCount mapRow( ResultSet rs, int rowNum ) throws SQLException{ 14 | WorkflowStatusCount object = new WorkflowStatusCount(); 15 | object.setWorkflowName( getString( rs, "workflow_name" ) ); 16 | object.setStatus( getWorkflowInstanceStatus( rs, "status" ) ); 17 | object.setCount( getInteger( rs, "count" ) ); 18 | return object; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/input/DueDateMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.input; 2 | 3 | import java.util.Date; 4 | 5 | import ee.telekom.workflow.graph.GraphInstance; 6 | 7 | public class DueDateMapping implements InputMapping{ 8 | 9 | private InputMapping delayMillisMapping; 10 | 11 | public DueDateMapping( long delayMillis ){ 12 | this( ConstantMapping.of( delayMillis ) ); 13 | } 14 | 15 | public DueDateMapping( InputMapping delayMillisMapping ){ 16 | this.delayMillisMapping = delayMillisMapping; 17 | } 18 | 19 | public InputMapping getDelayMillisMapping(){ 20 | return delayMillisMapping; 21 | } 22 | 23 | @Override 24 | public Date evaluate( GraphInstance instance ){ 25 | return new Date( System.currentTimeMillis() + delayMillisMapping.evaluate( instance ) ); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/gateway/XorJoin.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import ee.telekom.workflow.graph.GraphEngine; 4 | import ee.telekom.workflow.graph.Token; 5 | 6 | /** 7 | * Gateway, that may optionally be used in connection with {@link XorFork}s to increase the readability of graph definitions. 8 | */ 9 | public class XorJoin extends AbstractGateway{ 10 | 11 | public XorJoin( int id ){ 12 | super( id ); 13 | } 14 | 15 | public XorJoin( int id, String name ){ 16 | super( id, name ); 17 | } 18 | 19 | @Override 20 | public void execute( GraphEngine engine, Token token ){ 21 | engine.complete( token, null ); 22 | } 23 | 24 | @Override 25 | public void cancel( GraphEngine engine, Token token ){ 26 | // Tokens cannot "wait" at this kind of node. Hence, no "cancel" action is required. 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/AbstractNode.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node; 2 | 3 | import ee.telekom.workflow.graph.Node; 4 | 5 | /** 6 | * Abstract node implementation providing id and name. 7 | */ 8 | public abstract class AbstractNode implements Node{ 9 | 10 | private int id; 11 | private String name; 12 | 13 | public AbstractNode( int id ){ 14 | this( id, null ); 15 | } 16 | 17 | public AbstractNode( int id, String name ){ 18 | this.id = id; 19 | this.name = name; 20 | } 21 | 22 | @Override 23 | public int getId(){ 24 | return id; 25 | } 26 | 27 | @Override 28 | public String getName(){ 29 | return name; 30 | } 31 | 32 | @Override 33 | public String toString(){ 34 | return "[" + getClass().getSimpleName() + " id=" + id + (name == null ? "" : (", name=" + name)) + "]"; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/console/model/MbeanAttributeModel.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console.model; 2 | 3 | import java.io.Serializable; 4 | 5 | public class MbeanAttributeModel implements Serializable{ 6 | 7 | private static final long serialVersionUID = 1L; 8 | private String name; 9 | private String description; 10 | private Object value; 11 | 12 | public String getName(){ 13 | return name; 14 | } 15 | 16 | public void setName( String name ){ 17 | this.name = name; 18 | } 19 | 20 | public String getDescription(){ 21 | return description; 22 | } 23 | 24 | public void setDescription( String description ){ 25 | this.description = description; 26 | } 27 | 28 | public Object getValue(){ 29 | return value; 30 | } 31 | 32 | public void setValue( Object value ){ 33 | this.value = value; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/LoggingHandlerExceptionResolver.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web; 2 | 3 | import jakarta.servlet.http.HttpServletRequest; 4 | import jakarta.servlet.http.HttpServletResponse; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.web.servlet.ModelAndView; 9 | import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; 10 | 11 | public class LoggingHandlerExceptionResolver extends SimpleMappingExceptionResolver{ 12 | 13 | private static final Logger log = LoggerFactory.getLogger( LoggingHandlerExceptionResolver.class ); 14 | 15 | @Override 16 | protected ModelAndView doResolveException( HttpServletRequest request, HttpServletResponse response, Object handler, Exception e ){ 17 | log.info( "An unhandled exception occured", e ); 18 | return super.doResolveException( request, response, handler, e ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/abort/AbortService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.abort; 2 | 3 | import ee.telekom.workflow.core.common.UnexpectedStatusException; 4 | import ee.telekom.workflow.core.workflowinstance.WorkflowInstanceStatus; 5 | 6 | /** 7 | * Provides a service to request a workflow instance to become aborted. 8 | * 9 | * @author Christian Klock 10 | */ 11 | public interface AbortService{ 12 | 13 | /** 14 | * Requests a workflow instance to become aborted. 15 | *

16 | * This means, that its status is set to {@link WorkflowInstanceStatus#ABORT}. 17 | * Furthermore, if an error is associated with the instance, the error is deleted 18 | * and the instance is unlocked. 19 | * 20 | * @throws UnexpectedStatusException if changing the instance status does not work, e.g. because the instance is already EXECUTED. 21 | */ 22 | void abort( long woinRefNum ); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/producer/WorkProducerService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.producer; 2 | 3 | import java.util.List; 4 | 5 | import ee.telekom.workflow.core.workunit.WorkUnit; 6 | 7 | /** 8 | * Provides a service for the work unit producer. 9 | * 10 | * @author Christian Klock 11 | */ 12 | public interface WorkProducerService{ 13 | 14 | /** 15 | * Locks and queues new work units for processing. Removes the queued work units (max number limited by the maxBatchSize value) from the input list. 16 | * 17 | * @param unprocessedWorkUnits a list of work units which require locking and queuing 18 | * @param maxBatchSize max number of work units to produce in one run 19 | * @throws InterruptedException, if interrupted while adding work units to the work unit queue. 20 | */ 21 | void produceWork( List unprocessedWorkUnits, int maxBatchSize ) throws InterruptedException; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/resources/testApplicationContext-full.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/facade/workflowinstance/WorkflowStatusCount.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.workflowinstance; 2 | 3 | import ee.telekom.workflow.core.workflowinstance.WorkflowInstanceStatus; 4 | 5 | public class WorkflowStatusCount{ 6 | 7 | private String workflowName; 8 | private WorkflowInstanceStatus status; 9 | private int count; 10 | 11 | public String getWorkflowName(){ 12 | return workflowName; 13 | } 14 | 15 | public WorkflowInstanceStatus getStatus(){ 16 | return status; 17 | } 18 | 19 | public void setStatus( WorkflowInstanceStatus status ){ 20 | this.status = status; 21 | } 22 | 23 | public void setWorkflowName( String workflowName ){ 24 | this.workflowName = workflowName; 25 | } 26 | 27 | public int getCount(){ 28 | return count; 29 | } 30 | 31 | public void setCount( int count ){ 32 | this.count = count; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/gateway/condition/AttributeEqualsCondition.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway.condition; 2 | 3 | import org.apache.commons.lang3.ObjectUtils; 4 | 5 | import ee.telekom.workflow.graph.GraphInstance; 6 | 7 | public class AttributeEqualsCondition implements Condition{ 8 | 9 | private String attributeName; 10 | private Object testValue; 11 | 12 | public AttributeEqualsCondition( String attributeName, Object testValue ){ 13 | this.attributeName = attributeName; 14 | this.testValue = testValue; 15 | } 16 | 17 | public String getAttributeName(){ 18 | return attributeName; 19 | } 20 | 21 | public Object getTestValue(){ 22 | return testValue; 23 | } 24 | 25 | @Override 26 | public boolean evaluate( GraphInstance instance ){ 27 | return ObjectUtils.equals( instance.getEnvironment().getAttribute( attributeName ), testValue ); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/executor/lifeycle/MockLifecycleService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.lifeycle; 2 | 3 | import java.util.concurrent.atomic.AtomicBoolean; 4 | 5 | import ee.telekom.workflow.executor.lifecycle.LifecycleService; 6 | 7 | //Manually wired up in test application context 8 | public class MockLifecycleService implements LifecycleService{ 9 | 10 | private AtomicBoolean isStarted = new AtomicBoolean( false ); 11 | 12 | @Override 13 | public void startUp(){ 14 | isStarted.set( true ); 15 | } 16 | 17 | @Override 18 | public void shutDown(){ 19 | isStarted.set( false ); 20 | } 21 | 22 | @Override 23 | public void doHeartBeat(){ 24 | // Do nothing 25 | } 26 | 27 | @Override 28 | public void checkNodeStatus(){ 29 | // Do nothing 30 | } 31 | 32 | @Override 33 | public boolean isStarted(){ 34 | return isStarted.get(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/resources/workflow-engine-jta.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/GraphWorkItemEventListener.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | import ee.telekom.workflow.core.workitem.WorkItem; 4 | 5 | /** 6 | * Listener interface for events in the life cycle of a {@link WorkItem}. 7 | */ 8 | public interface GraphWorkItemEventListener{ 9 | 10 | /** 11 | * Called after a new work item was created 12 | * 13 | * @param instance 14 | * the newly created work item 15 | */ 16 | void onCreated( GraphWorkItem workItem ); 17 | 18 | /** 19 | * Called after a work item was cancelled 20 | * 21 | * @param instance 22 | * the cancelled work item 23 | */ 24 | void onCancelled( GraphWorkItem workItem ); 25 | 26 | /** 27 | * Called after a work item was completed 28 | * 29 | * @param instance 30 | * the completed work item 31 | */ 32 | void onCompleted( GraphWorkItem workItem ); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/console/WorkflowDefinitionsController.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.ui.Model; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | 8 | import ee.telekom.workflow.facade.WorkflowEngineFacade; 9 | import ee.telekom.workflow.facade.model.WorkflowInstanceFacadeStatus; 10 | 11 | @Controller 12 | @RequestMapping("/console") 13 | public class WorkflowDefinitionsController{ 14 | 15 | @Autowired 16 | private WorkflowEngineFacade facade; 17 | 18 | @RequestMapping("/workflow/definitions") 19 | public String viewWorkflowDefinitions( Model model ){ 20 | model.addAttribute( "workflows", facade.getWorkflowStatistics() ); 21 | model.addAttribute( "statuses", WorkflowInstanceFacadeStatus.values() ); 22 | return "console/workflow/definitions"; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/input/AttributeMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.input; 2 | 3 | import ee.telekom.workflow.graph.GraphInstance; 4 | 5 | /** 6 | * InputMapping for an attribute's value in the given environment. 7 | *

8 | * NB! At the time of writing, this AttributeMapping is actually not usable via the workflow engine API (DSL). ExpressionLanguageMapping is used instead. 9 | */ 10 | public class AttributeMapping implements InputMapping{ 11 | 12 | private String attributeName; 13 | 14 | public AttributeMapping( String attributeName ){ 15 | this.attributeName = attributeName; 16 | } 17 | 18 | public String getAttributeName(){ 19 | return attributeName; 20 | } 21 | 22 | @Override 23 | public T evaluate( GraphInstance instance ){ 24 | @SuppressWarnings("unchecked") 25 | T attribute = (T)instance.getEnvironment().getAttribute( attributeName ); 26 | return attribute; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/workunit/WorkUnitRowMapper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.workunit; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | import ee.telekom.workflow.util.AbstractRowMapper; 7 | 8 | public class WorkUnitRowMapper extends AbstractRowMapper{ 9 | 10 | public static final WorkUnitRowMapper INSTANCE = new WorkUnitRowMapper(); 11 | 12 | @Override 13 | public WorkUnit mapRow( ResultSet rs, int rowNum ) throws SQLException{ 14 | WorkUnit object = new WorkUnit(); 15 | object.setWoinRefNum( getLong( rs, "woin_ref_num" ) ); 16 | object.setType( getWorkType( rs, "type" ) ); 17 | object.setWoitRefNum( getLong( rs, "woit_ref_num" ) ); 18 | return object; 19 | } 20 | 21 | private WorkType getWorkType( ResultSet rs, String columnLabel ) throws SQLException{ 22 | String value = rs.getString( columnLabel ); 23 | return value == null ? null : WorkType.valueOf( value ); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/AbstractDao.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | import javax.sql.DataSource; 4 | 5 | import org.springframework.jdbc.core.JdbcTemplate; 6 | import org.springframework.jdbc.core.namedparam.NamedParameterJdbcDaoSupport; 7 | import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; 8 | 9 | public class AbstractDao{ 10 | 11 | private NamedParameterJdbcDaoSupport daoSupport; 12 | 13 | public void setDataSource( DataSource dataSource ){ 14 | daoSupport = new NamedParameterJdbcDaoSupport(); 15 | daoSupport.setDataSource( dataSource ); 16 | } 17 | 18 | public DataSource getDataSource(){ 19 | return daoSupport.getDataSource(); 20 | } 21 | 22 | protected JdbcTemplate getJdbcTemplate(){ 23 | return daoSupport.getJdbcTemplate(); 24 | } 25 | 26 | protected NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(){ 27 | return daoSupport.getNamedParameterJdbcTemplate(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/DslIfBlock.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface DslIfBlock extends DslBlock>{ 12 | 13 | /** 14 | * If the given condition evaluates to true, then executes the branch content and ignores the other elseIf and else branches, otherwise evaluates the 15 | * following elseIf or else condition. 16 | * 17 | * @param condition expression language condition ("EL_EXPRESSION") 18 | */ 19 | DslIfBlock elseIf( String condition ); 20 | 21 | /** 22 | * The default execution branch for the cases when _if and elseIf branches evaluated all to false. 23 | */ 24 | DslElseBlock else_(); 25 | 26 | /** 27 | * Block end tag, closes the previously started if-elseIf-else-endIf block. 28 | */ 29 | Level endIf(); 30 | 31 | } 32 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/ExceptionUtil.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | import org.apache.commons.lang3.exception.ExceptionUtils; 4 | 5 | import ee.telekom.workflow.graph.WorkflowException; 6 | 7 | public class ExceptionUtil{ 8 | 9 | public static String getErrorText( Exception exception ){ 10 | Throwable cause = getWorkflowCause( exception ); 11 | return cause == null ? exception.getMessage() : cause.getMessage(); 12 | } 13 | 14 | public static String getErrorDetails( Exception exception ){ 15 | return ExceptionUtils.getStackTrace( exception ); 16 | } 17 | 18 | /** 19 | * Finds the first cause in the exception hierarchy that is not an instance 20 | * of {@link WorkflowException}. 21 | */ 22 | private static Throwable getWorkflowCause( Exception exception ){ 23 | Throwable e = exception; 24 | while( e instanceof WorkflowException ){ 25 | e = e.getCause(); 26 | } 27 | return e; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/util/LogbackStopListener.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.util; 2 | 3 | import jakarta.servlet.ServletContextEvent; 4 | import jakarta.servlet.ServletContextListener; 5 | 6 | import org.slf4j.LoggerFactory; 7 | 8 | import ch.qos.logback.classic.LoggerContext; 9 | 10 | /** 11 | * Servlet context destory hook: stop logback to properly release resources. 12 | * 13 | * @author Erko Hansar 14 | * @see http://logback.qos.ch/manual/configuration.html#stopContext 15 | */ 16 | public class LogbackStopListener implements ServletContextListener{ 17 | 18 | @Override 19 | public void contextInitialized( ServletContextEvent sce ){ 20 | // nothing to do here 21 | } 22 | 23 | @Override 24 | public void contextDestroyed( ServletContextEvent sce ){ 25 | // assume SLF4J is bound to logback-classic in the current environment 26 | LoggerContext loggerContext = (LoggerContext)LoggerFactory.getILoggerFactory(); 27 | loggerContext.stop(); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/console/form/SearchWorkflowInstancesForm.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console.form; 2 | 3 | import java.util.List; 4 | 5 | import ee.telekom.workflow.facade.model.SearchWorkflowInstances; 6 | 7 | public class SearchWorkflowInstancesForm extends SearchWorkflowInstances{ 8 | 9 | private static final long serialVersionUID = 1L; 10 | 11 | private List id; 12 | 13 | public List getId(){ 14 | return id; 15 | } 16 | 17 | public void setId( List id ){ 18 | this.id = id; 19 | } 20 | 21 | public boolean hasSearchCriteria(){ 22 | return getRefNum() != null && getRefNum().size() > 0 || getWorkflowName() != null && getWorkflowName().size() > 0 || getLabel1() != null && getLabel1().size() > 0 23 | || getLabel2() != null && getLabel2().size() > 0 || getStatus() != null && getStatus().size() > 0; 24 | } 25 | 26 | public boolean hasId(){ 27 | return getId() != null && getId().size() > 0; 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/listener/WorkflowInstanceEventListener.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.listener; 2 | 3 | /** 4 | * Provides a listener that is notified when workflow instance lifecycle events occur. 5 | * 6 | * @author Christian Klock 7 | */ 8 | public interface WorkflowInstanceEventListener{ 9 | 10 | /** 11 | * Called before a workflow instance is started. 12 | * 13 | * @param event 14 | * information on the instance being started 15 | */ 16 | void onStarting( WorkflowInstanceEvent event ); 17 | 18 | /** 19 | * Called after a workflow instance was aborted. 20 | * 21 | * @param event 22 | * information on the aborted instance 23 | */ 24 | void onAborted( WorkflowInstanceEvent event ); 25 | 26 | /** 27 | * Called after a workflow instance's execution finishes. 28 | * 29 | * @param event 30 | * information on the completed instance 31 | */ 32 | void onExecuted( WorkflowInstanceEvent event ); 33 | 34 | } 35 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/node/NodeRowMapper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.node; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | import ee.telekom.workflow.core.workflowinstance.WorkflowInstance; 7 | import ee.telekom.workflow.util.AbstractRowMapper; 8 | 9 | /** 10 | * Row mapper for {@link WorkflowInstance}s that maps all database fields. 11 | * 12 | * @author Christian Klock 13 | */ 14 | public class NodeRowMapper extends AbstractRowMapper{ 15 | 16 | public static final NodeRowMapper INSTANCE = new NodeRowMapper(); 17 | 18 | @Override 19 | public Node mapRow( ResultSet rs, int rowNum ) throws SQLException{ 20 | Node object = new Node(); 21 | object.setRefNum( getLong( rs, "ref_num" ) ); 22 | object.setNodeName( getString( rs, "node_name" ) ); 23 | object.setClusterName( getString( rs, "cluster_name" ) ); 24 | object.setStatus( getNodeStatus( rs, "status" ) ); 25 | object.setHeartbeat( getDate( rs, "heartbeat" ) ); 26 | return object; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/node/NodeStatus.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.node; 2 | 3 | /** 4 | * Nodes regularly check their status and start/stop working based on the status 5 | * stored in a database. This enables one node to start/stop other nodes. 6 | */ 7 | public enum NodeStatus{ 8 | 9 | /** 10 | * The node should start working when it next time checks its status. 11 | */ 12 | ENABLE, 13 | 14 | /** 15 | * The node has started working. 16 | * A node in this status is considered dead, if it does not regularly update its heartbeat. 17 | */ 18 | ENABLED, 19 | 20 | /** 21 | * The node should stop working when it next time checks its status. 22 | */ 23 | DISABLE, 24 | 25 | /** 26 | * The node has stopped working. 27 | */ 28 | DISABLED, 29 | 30 | /** 31 | * A node is marked considered failed/dead if it ENABLED but does not regularly update its heartbeat. 32 | * The cluster's master regularly check's whether other nodes to this end. 33 | */ 34 | FAILED 35 | 36 | } 37 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/marshall/TokenState.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.marshall; 2 | 3 | /** 4 | * Helper class to serialize the state of tokens. 5 | * 6 | * @author Christian Klock 7 | */ 8 | public class TokenState{ 9 | 10 | private int id; 11 | private int nodeId; 12 | private Integer parentId; 13 | private boolean isActive; 14 | 15 | public int getId(){ 16 | return id; 17 | } 18 | 19 | public void setId( int id ){ 20 | this.id = id; 21 | } 22 | 23 | public int getNodeId(){ 24 | return nodeId; 25 | } 26 | 27 | public void setNodeId( int nodeId ){ 28 | this.nodeId = nodeId; 29 | } 30 | 31 | public Integer getParentId(){ 32 | return parentId; 33 | } 34 | 35 | public void setParentId( Integer parentId ){ 36 | this.parentId = parentId; 37 | } 38 | 39 | public boolean isActive(){ 40 | return isActive; 41 | } 42 | 43 | public void setActive( boolean isActive ){ 44 | this.isActive = isActive; 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /telekom-workflow-example/src/main/resources/example-plugin-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/Transition.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | /** 4 | * A {@link Transition} describes the order of execution between {@link Node}s. 5 | * They are directed links between nodes. During the execution of a 6 | * {@link GraphInstance}, transitions will determine the path tokens proceed 7 | * between nodes. 8 | *

9 | * Transitions may be labelled with a name. Their name can be used for flow control. 10 | */ 11 | public interface Transition { 12 | 13 | public static final String DEFAULT_TRANSITION_NAME = null; 14 | 15 | /** 16 | * Returns the {@link Node} at the start of the transition. 17 | * 18 | * @return the {@link Node} at the start of the transition 19 | */ 20 | Node getStartNode(); 21 | 22 | /** 23 | * Returns the {@link Node} at the end of the transition. 24 | * 25 | * @return the {@link Node} at the end of the transition 26 | */ 27 | Node getEndNode(); 28 | 29 | /** 30 | * Returns the transition name. Nulls and blanks are allowed. 31 | * 32 | * @return the transition name 33 | */ 34 | String getName(); 35 | 36 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/workitem/WorkItemService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.workitem; 2 | 3 | import java.util.List; 4 | 5 | import ee.telekom.workflow.core.common.UnexpectedStatusException; 6 | 7 | public interface WorkItemService{ 8 | 9 | WorkItem find( long refNum ); 10 | 11 | List findActiveByWoinRefNum( long woinRefNum ); 12 | 13 | WorkItem findActiveByWoinRefNumAndTokenId( long woinRefNum, int tokenId ); 14 | 15 | void markExecuting( long refNum ); 16 | 17 | void markExecutedAndSaveResult( long refNum, String result ); 18 | 19 | void markCompleting( long refNum ); 20 | 21 | void markCompleted( long refNum ); 22 | 23 | void markCancelled( long refNum ); 24 | 25 | void handleExecutingError( long woinRefNum, long woitRefNum, Exception e ); 26 | 27 | void handleCompletingError( long woinRefNum, long woitRefNum, Exception e ); 28 | 29 | void rewindAfterError( long refNum ) throws UnexpectedStatusException; 30 | 31 | void recoverExecuting( String nodeName ); 32 | 33 | void recoverCompleting( String nodeName ); 34 | 35 | } 36 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/listener/HumanTaskEventListener.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.listener; 2 | 3 | /** 4 | * Provides a listener that is notified when human task lifecycle events occur. 5 | * 6 | * @author Christian Klock 7 | */ 8 | public interface HumanTaskEventListener{ 9 | 10 | /** 11 | * Called after a human task was created. 12 | * 13 | * @param event 14 | * information on the created human task 15 | */ 16 | void onCreated( HumanTaskEvent event ); 17 | 18 | /** 19 | * Called after a human task was completed. 20 | * 21 | * @param event 22 | * information on the created human task 23 | * @param humanTaskResult 24 | * the result that was submitted when completing the human task 25 | */ 26 | void onCompleted( HumanTaskEvent event, Object humanTaskResult ); 27 | 28 | /** 29 | * Called after a human task was cancelled. 30 | * 31 | * @param event 32 | * information on the created human task 33 | */ 34 | void onCancelled( HumanTaskEvent event ); 35 | 36 | } 37 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/NamedPoolThreadFactory.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | import java.util.concurrent.ThreadFactory; 4 | import java.util.concurrent.atomic.AtomicInteger; 5 | 6 | public class NamedPoolThreadFactory implements ThreadFactory{ 7 | private final ThreadGroup group; 8 | private final AtomicInteger threadNumber = new AtomicInteger( 1 ); 9 | private final String namePrefix; 10 | 11 | public NamedPoolThreadFactory( String poolName ){ 12 | SecurityManager s = System.getSecurityManager(); 13 | group = (s != null) ? s.getThreadGroup() : 14 | Thread.currentThread().getThreadGroup(); 15 | this.namePrefix = poolName + "-"; 16 | } 17 | 18 | @Override 19 | public Thread newThread( Runnable r ){ 20 | Thread t = new Thread( group, r, namePrefix + threadNumber.getAndIncrement(), 0 ); 21 | if( t.isDaemon() ){ 22 | t.setDaemon( false ); 23 | } 24 | if( t.getPriority() != Thread.NORM_PRIORITY ){ 25 | t.setPriority( Thread.NORM_PRIORITY ); 26 | } 27 | return t; 28 | } 29 | } -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/tags/menu.tag: -------------------------------------------------------------------------------- 1 | <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 2 | <%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> 3 | <%@ taglib prefix="workflow-ui" uri="http://telekom.ee/tags/workflow" %> 4 | <%@ attribute name="activeTab" required="false" %> 5 | 6 |

21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 AS Eesti Telekom 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/input/ArrayMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.input; 2 | 3 | import ee.telekom.workflow.graph.GraphInstance; 4 | 5 | /** 6 | * InputMapping that evaluates to an array. The class is mainly intended to created argument maps for tasks and method call activities. 7 | */ 8 | public class ArrayMapping implements InputMapping{ 9 | 10 | private InputMapping[] elementMappings; 11 | 12 | public ArrayMapping( InputMapping[] elementMappings ){ 13 | this.elementMappings = elementMappings; 14 | } 15 | 16 | public InputMapping[] getElementMappings(){ 17 | return elementMappings; 18 | } 19 | 20 | @Override 21 | public Object[] evaluate( GraphInstance instance ){ 22 | if( elementMappings == null || elementMappings.length == 0 ){ 23 | return null; 24 | } 25 | Object[] array = new Object[elementMappings.length]; 26 | for( int i = 0; i < elementMappings.length; i++ ){ 27 | array[i] = elementMappings[i].evaluate( instance ); 28 | } 29 | return array; 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/facade/workflowinstance/WorkflowInstancesDataTableColumnMapper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.workflowinstance; 2 | 3 | public enum WorkflowInstancesDataTableColumnMapper { 4 | 5 | REF_NUM(1, "ref_num"), 6 | NAME(2, "workflow_name"), 7 | LABEL1(3, "label1"), 8 | LABEL2(4, "label2"), 9 | DATE_CREATED(5, "date_created"), 10 | STATUS(8, "status"); 11 | 12 | private int columnId; 13 | private String fieldName; 14 | 15 | WorkflowInstancesDataTableColumnMapper( int columnId, String fieldName ){ 16 | this.columnId = columnId; 17 | this.fieldName = fieldName; 18 | } 19 | 20 | public static WorkflowInstancesDataTableColumnMapper from( int columnId ){ 21 | for( WorkflowInstancesDataTableColumnMapper type : values() ){ 22 | if( type.columnId == columnId ){ 23 | return type; 24 | } 25 | } 26 | return DATE_CREATED; 27 | } 28 | 29 | public String getFieldName(){ 30 | return fieldName; 31 | } 32 | 33 | public int getColumnId(){ 34 | return columnId; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/SimpleLifeCycleBean.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | import org.springframework.context.SmartLifecycle; 4 | 5 | public abstract class SimpleLifeCycleBean implements SmartLifecycle{ 6 | 7 | private static final int DEFAULT_PHASE = 1; 8 | 9 | private final int phase = DEFAULT_PHASE; 10 | private boolean running = false; 11 | 12 | public abstract void doStart(); 13 | 14 | public abstract void doStop(); 15 | 16 | @Override 17 | public final void start(){ 18 | doStart(); 19 | running = true; 20 | } 21 | 22 | @Override 23 | public final void stop(){ 24 | doStop(); 25 | running = false; 26 | } 27 | 28 | @Override 29 | public boolean isRunning(){ 30 | return running; 31 | } 32 | 33 | @Override 34 | public int getPhase(){ 35 | return phase; 36 | } 37 | 38 | @Override 39 | public boolean isAutoStartup(){ 40 | return true; 41 | } 42 | 43 | @Override 44 | public void stop( Runnable callback ){ 45 | stop(); 46 | callback.run(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/facade/model/WorkflowInstanceFacadeStatus.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.model; 2 | 3 | /** 4 | * Enumeration of workflow instance statuses. 5 | * 6 | * The given statuses are not the same statuses as used by the engine internally and the one provided by 7 | * {@link WorkflowInstanceState#getStatus()}. The given statuses summarize the internal statuses to 8 | * hide internal details and give an easier meaning. 9 | * 10 | * @author Christian Klock 11 | * 12 | */ 13 | public enum WorkflowInstanceFacadeStatus{ 14 | /** 15 | * The workflow instance is active and therefore subject to execution. 16 | */ 17 | ACTIVE, 18 | /** 19 | * The workflow instance is in an error status. It's execution is halted until the error is resolved. 20 | */ 21 | ERROR, 22 | /** 23 | * The workflow instance execution is suspended. 24 | */ 25 | SUSPENDED, 26 | /** 27 | * The workflow instance is in a final state. It is aborted. 28 | */ 29 | ABORTED, 30 | /** 31 | * The workflow instance is in a final state. It is fully executed. 32 | */ 33 | EXECUTED; 34 | } -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/IndexController.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | 7 | import ee.telekom.workflow.core.common.WorkflowEngineConfiguration; 8 | 9 | @Controller 10 | public class IndexController{ 11 | 12 | @Autowired 13 | private WorkflowEngineConfiguration configuration; 14 | 15 | @RequestMapping("/") 16 | public String serveIndex1(){ 17 | return "redirect:" + configuration.getConsoleMappingPrefix() + "/console/status"; 18 | } 19 | 20 | @RequestMapping("/console") 21 | public String serveIndex2(){ 22 | return "redirect:" + configuration.getConsoleMappingPrefix() + "/console/status"; 23 | } 24 | 25 | @RequestMapping("/console/") 26 | public String serveIndex3(){ 27 | return "redirect:" + configuration.getConsoleMappingPrefix() + "/console/status"; 28 | } 29 | 30 | @RequestMapping(value = "/login") 31 | public String serveLoginPage(){ 32 | return "login"; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/core/TransitionImpl.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.core; 2 | 3 | import ee.telekom.workflow.graph.Node; 4 | import ee.telekom.workflow.graph.Transition; 5 | 6 | public class TransitionImpl implements Transition{ 7 | 8 | private String name; 9 | private Node startNode; 10 | private Node endNode; 11 | 12 | public TransitionImpl( Node startNode, Node endNode ){ 13 | this( Transition.DEFAULT_TRANSITION_NAME, startNode, endNode ); 14 | } 15 | 16 | public TransitionImpl( String name, Node startNode, Node endNode ){ 17 | this.name = name; 18 | this.startNode = startNode; 19 | this.endNode = endNode; 20 | } 21 | 22 | @Override 23 | public String getName(){ 24 | return name; 25 | } 26 | 27 | @Override 28 | public Node getStartNode(){ 29 | return startNode; 30 | } 31 | 32 | @Override 33 | public Node getEndNode(){ 34 | return endNode; 35 | } 36 | 37 | @Override 38 | public String toString(){ 39 | return "[Transition name='" + name + "', start=" + startNode + ", end=" + endNode + "]"; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/resources/testApplicationContext.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/node/gateway/_05_SimpleMergeTest.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import org.junit.Test; 4 | 5 | import ee.telekom.workflow.graph.AbstractGraphTest; 6 | import ee.telekom.workflow.graph.GraphFactory; 7 | 8 | public class _05_SimpleMergeTest extends AbstractGraphTest { 9 | 10 | @Test 11 | public void one() { 12 | assertConditionalExecution(GraphFactory.INSTANCE.simplemerge_one(), 13 | null, "2"); 14 | } 15 | 16 | @Test 17 | public void one_post() { 18 | assertConditionalExecution( 19 | GraphFactory.INSTANCE.simplemerge_one_post(), null, "2,4"); 20 | } 21 | 22 | @Test 23 | public void two() { 24 | assertConditionalExecution(GraphFactory.INSTANCE.simplemerge_two(), 25 | GraphFactory.VALUE1, "2"); 26 | 27 | assertConditionalExecution(GraphFactory.INSTANCE.simplemerge_two(), 28 | null, "3"); 29 | } 30 | 31 | @Test 32 | public void two_post() { 33 | assertConditionalExecution( 34 | GraphFactory.INSTANCE.simplemerge_two_post(), 35 | GraphFactory.VALUE1, "2,5"); 36 | 37 | assertConditionalExecution( 38 | GraphFactory.INSTANCE.simplemerge_two_post(), null, "3,5"); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/console/model/DataTable.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console.model; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public class DataTable{ 7 | 8 | private int draw; 9 | private int recordsTotal; 10 | private int recordsFiltered; 11 | private List data = new ArrayList<>(); 12 | 13 | public int getDraw(){ 14 | return draw; 15 | } 16 | 17 | public void setDraw( int draw ){ 18 | this.draw = draw; 19 | } 20 | 21 | public int getRecordsTotal(){ 22 | return recordsTotal; 23 | } 24 | 25 | public void setRecordsTotal( int recordsTotal ){ 26 | this.recordsTotal = recordsTotal; 27 | } 28 | 29 | public int getRecordsFiltered(){ 30 | return recordsFiltered; 31 | } 32 | 33 | public void setRecordsFiltered( int recordsFiltered ){ 34 | this.recordsFiltered = recordsFiltered; 35 | } 36 | 37 | public List getData(){ 38 | return data; 39 | } 40 | 41 | public void setData( List data ){ 42 | this.data = data; 43 | } 44 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/AbstractWorkflowEngineDao.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | import javax.sql.DataSource; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.beans.factory.annotation.Qualifier; 7 | 8 | import ee.telekom.workflow.core.common.WorkflowEngineConfiguration; 9 | 10 | public class AbstractWorkflowEngineDao extends AbstractDao{ 11 | 12 | @Autowired 13 | private WorkflowEngineConfiguration config; 14 | 15 | @Override 16 | @Autowired 17 | public void setDataSource( @Qualifier("workflowengineDataSource") DataSource dataSource ){ 18 | super.setDataSource( dataSource ); 19 | } 20 | 21 | public String getCreatedOrLastUpdatedBy(){ 22 | return config.getNodeName(); 23 | } 24 | 25 | protected String getClusterName(){ 26 | return config.getClusterName(); 27 | } 28 | 29 | protected long getNextSequenceValue( String sequence ){ 30 | return getJdbcTemplate().queryForObject( "SELECT nextval('" + sequence + "')", Long.class ); 31 | } 32 | 33 | protected String getSchema() { 34 | return config.getSchema(); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/error/ExecutionErrorRowMapper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.error; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | import ee.telekom.workflow.util.AbstractRowMapper; 7 | 8 | /** 9 | * Row mapper for {@link ExecutionError}s that maps all database fields except the 10 | * ones that are not used by the internal parts of the engine (date_created, created_by). 11 | * 12 | * @author Christian Klock 13 | */ 14 | public class ExecutionErrorRowMapper extends AbstractRowMapper{ 15 | 16 | public static final ExecutionErrorRowMapper INSTANCE = new ExecutionErrorRowMapper(); 17 | 18 | @Override 19 | public ExecutionError mapRow( ResultSet rs, int rowNum ) throws SQLException{ 20 | ExecutionError object = new ExecutionError(); 21 | object.setRefNum( getLong( rs, "ref_num" ) ); 22 | object.setWoinRefNum( getLong( rs, "woin_ref_num" ) ); 23 | object.setWoitRefNum( getLong( rs, "woit_ref_num" ) ); 24 | object.setErrorText( getString( rs, "error_text" ) ); 25 | object.setErrorDetails( getString( rs, "error_details" ) ); 26 | return object; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/recovery/RecoveryService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.recovery; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Service method for recovering from engine failures. The engine may fail 7 | * or leave data in an inconsistent state if it is not shutdown in a clean way 8 | * or if there are other hardware/network failures. 9 | * 10 | * Two kinds of problems may arise from such a failure scenario. 11 | *
    12 | *
  1. A workflow instance is locked and assigned to a node but the node has failed/is dead. 13 | *
  2. A workflow instance is locked AND it is not in the queue AND it is not assigned to a node. 14 | *
      15 | */ 16 | public interface RecoveryService{ 17 | 18 | /** 19 | * Recovers all workflow instance's with the first above mentioned problem. 20 | * @param deadNodes the nodes that are dead/failed. 21 | */ 22 | void recoverExecutionsAssignedToNodes( List deadNodes ); 23 | 24 | /** 25 | * Recovers all workflow instance's with the second above mentioned problem. 26 | * @param clusterName this cluster's name 27 | */ 28 | void recoverExecutionsNotAssignedToNodes( String clusterName ); 29 | 30 | } 31 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/lifecycle/LifecycleService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.lifecycle; 2 | 3 | /** 4 | * The engines central life cycle manager that implements a start-up and shut-down order 5 | * for the different engine's components (considering the interdependencies). 6 | */ 7 | public interface LifecycleService{ 8 | 9 | /** 10 | * Called at deployment. Starts the engine's components if required and possible. 11 | */ 12 | void startUp(); 13 | 14 | /** 15 | * Called at undeployment. Stops the engine's components if required. 16 | */ 17 | void shutDown(); 18 | 19 | /** 20 | * Called regularly to write a heart beat timestamp to database node table. 21 | */ 22 | void doHeartBeat(); 23 | 24 | /** 25 | * Called regularly to 26 | * - mark dead cluster siblings as FAILED. 27 | * - heal workflow instance's if there is a FAILED node. 28 | * - test whether the engine's is still master or not anymore and to start/stop components accordingly if required. 29 | */ 30 | void checkNodeStatus(); 31 | 32 | /** 33 | * Returns whether the engine is started. 34 | */ 35 | boolean isStarted(); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/gateway/AbstractConditionalGateway.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.apache.commons.lang3.tuple.Pair; 7 | 8 | import ee.telekom.workflow.graph.node.gateway.condition.Condition; 9 | 10 | /** 11 | * Abstract gateway that is providing common functionality for gateways 12 | * that support conditional transitions. 13 | */ 14 | public abstract class AbstractConditionalGateway extends AbstractGateway{ 15 | 16 | private List> conditions = new ArrayList>(); 17 | 18 | public AbstractConditionalGateway( int id ){ 19 | super( id ); 20 | } 21 | 22 | public AbstractConditionalGateway( int id, String name ){ 23 | super( id, name ); 24 | } 25 | 26 | public List> getConditions(){ 27 | return conditions; 28 | } 29 | 30 | /** 31 | * A null condition is interpreted as a default condition. 32 | */ 33 | public void addCondition( Condition condition, String transitionName ){ 34 | conditions.add( Pair.of( condition, transitionName ) ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/GraphInstanceEventListener.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | /** 4 | * Listener interface for events in the life cycle of a {@link GraphInstance}. 5 | */ 6 | public interface GraphInstanceEventListener { 7 | 8 | /** 9 | * Called after a new graph instance was created 10 | * 11 | * @param instance 12 | * the newly created instance 13 | */ 14 | void onCreated(GraphInstance instance); 15 | 16 | /** 17 | * Called after a graph instance was started. 18 | * 19 | * @param instance 20 | * the started instance 21 | */ 22 | void onStarted(GraphInstance instance); 23 | 24 | /** 25 | * Called before a graph instance is aborted 26 | * 27 | * @param instance 28 | * the instance being aborted 29 | */ 30 | void onAborting(GraphInstance instance); 31 | 32 | /** 33 | * Called after a graph instance was aborted 34 | * 35 | * @param instance 36 | * the aborted instance 37 | */ 38 | void onAborted(GraphInstance instance); 39 | 40 | /** 41 | * Called after a graph instance's execution completed 42 | * 43 | * @param instance 44 | * the completed instance 45 | */ 46 | void onCompleted(GraphInstance instance); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /telekom-workflow-example/src/main/java/ee/telekom/workflow/example/definition/ExampleStepSelector.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.example.definition; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Component; 5 | 6 | import ee.telekom.workflow.example.service.CustomerService; 7 | 8 | @Component 9 | public class ExampleStepSelector{ 10 | 11 | @Autowired 12 | private CustomerService customerService; 13 | 14 | public String findNextStep( String customerId, String currentStepId ){ 15 | if( "00".equals( currentStepId ) ){ 16 | String customerStatus = customerService.getCustomerStatus( customerId ); 17 | if( "ACTIVE".equalsIgnoreCase( customerStatus ) ){ 18 | return Example_01_SendWarning.class.getCanonicalName(); 19 | } 20 | else{ 21 | return Example_03_CreateSchedule.class.getCanonicalName(); 22 | } 23 | } 24 | else if( "01".equals( currentStepId ) ){ 25 | return Example_02_Suspend.class.getCanonicalName(); 26 | } 27 | else if( "02".equals( currentStepId ) ){ 28 | return Example_03_CreateSchedule.class.getCanonicalName(); 29 | } 30 | throw new IllegalArgumentException( "No matching next step!" ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/common/UnexpectedStatusException.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.common; 2 | 3 | import java.util.Collection; 4 | 5 | /** 6 | * Exception thrown when an entity (e.g. a workflow instance or a work item) 7 | * is not found in the expected status in the database during an UPDATE 8 | * statement. 9 | *

      10 | * Throwing this type of exception can be considered an optimistic locking 11 | * failure. A retry of the update is generally not possible. 12 | * 13 | * @author Christian Klock 14 | */ 15 | public class UnexpectedStatusException extends RuntimeException{ 16 | 17 | private static final long serialVersionUID = 1L; 18 | 19 | private static final String MSG = "The attempted update failed. Error: %s. This may be caused by a concurrent update."; 20 | 21 | public UnexpectedStatusException( String error ) { 22 | super( String.format( MSG, error ) ); 23 | } 24 | 25 | public UnexpectedStatusException( Object expectedStatus ){ 26 | this( "The entity was not in the expected status (" + expectedStatus.toString() + ")" ); 27 | } 28 | 29 | public UnexpectedStatusException( Collection expectedStatuses ){ 30 | this( "The entity was not in one of the expected status (" + expectedStatuses.toString() + ")" ); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/el/EnvironmentBeanNameResolver.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.el; 2 | 3 | import jakarta.el.BeanNameResolver; 4 | 5 | import ee.telekom.workflow.graph.Environment; 6 | 7 | /** 8 | * A custom Expression Language 3.0 BeanNameResolver that lives on top of Environment instance. Used when evaluating conditions and attribute expressions. 9 | * 10 | * @author Erko Hansar 11 | */ 12 | public class EnvironmentBeanNameResolver extends BeanNameResolver{ 13 | 14 | private Environment environment; 15 | 16 | public EnvironmentBeanNameResolver( Environment environment ){ 17 | this.environment = environment; 18 | } 19 | 20 | @Override 21 | public boolean isNameResolved( String beanName ){ 22 | return environment.containsAttribute( beanName ); 23 | } 24 | 25 | @Override 26 | public Object getBean( String beanName ){ 27 | return environment.getAttribute( beanName ); 28 | } 29 | 30 | @Override 31 | public void setBeanValue( String beanName, Object value ){ 32 | environment.setAttribute( beanName, value ); 33 | } 34 | 35 | @Override 36 | public boolean isReadOnly( String beanName ){ 37 | return false; 38 | } 39 | 40 | @Override 41 | public boolean canCreateBean( String beanName ){ 42 | return true; 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/listener/WorkflowInstanceEvent.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.listener; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Provides details on the workflow instance associated with the event, the workflow instance's id, 7 | * the workflow's name and version and the instance's current attributes (the instance's internal memory). 8 | * 9 | * The attributes must be used read-only! 10 | * 11 | * @author Christian Klock 12 | */ 13 | public class WorkflowInstanceEvent{ 14 | 15 | private Long woinRefNum; 16 | private String workflowName; 17 | private Integer workflowVersion; 18 | private Map attributes; 19 | 20 | public WorkflowInstanceEvent( Long woinRefNum, String workflowName, Integer workflowVersion, Map attributes ){ 21 | this.woinRefNum = woinRefNum; 22 | this.workflowName = workflowName; 23 | this.workflowVersion = workflowVersion; 24 | this.attributes = attributes; 25 | } 26 | 27 | public Long getWoinRefNum(){ 28 | return woinRefNum; 29 | } 30 | 31 | public String getWorkflowName(){ 32 | return workflowName; 33 | } 34 | 35 | public Integer getWorkflowVersion(){ 36 | return workflowVersion; 37 | } 38 | 39 | public Map getAttributes(){ 40 | return attributes; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/producer/WorkProducerJob.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.producer; 2 | 3 | import ee.telekom.workflow.executor.consumer.WorkConsumerJob; 4 | 5 | /** 6 | * Provides the life cycle methods of the engines work unit producer part. 7 | *

      8 | * See also {@link WorkConsumerJob}. 9 | * 10 | * @author Christian Klock 11 | */ 12 | public interface WorkProducerJob{ 13 | 14 | /** 15 | * Starts the producer. 16 | *

      17 | * Make sure you call {@link #stop()} for a clean shutdown if you called this method. 18 | * Once stopped, this method can be used to restart the producer. 19 | */ 20 | void start(); 21 | 22 | /** 23 | * Stops the producer. Is a no-op, if the producer is already stopped. 24 | */ 25 | void stop(); 26 | 27 | /** 28 | * Returns whether the producer is currently started. 29 | */ 30 | boolean isStarted(); 31 | 32 | /** 33 | * Suspends the producer without shutting it down. Resume the producer in order to 34 | * let it continue to produce work units. 35 | */ 36 | void suspend(); 37 | 38 | /** 39 | * Resumes the producer. Is a no-op for a not suspended producer. 40 | */ 41 | void resume(); 42 | 43 | /** 44 | * Returns whether the producer is currently suspended. 45 | */ 46 | boolean isSuspended(); 47 | 48 | } 49 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/RecordPathScript.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | import ee.telekom.workflow.graph.node.activity.ScriptActivity.Script; 4 | 5 | /** 6 | * This {@link Script} appends the given id to the "path" attribute of the {@link Environment} 7 | * UNLESS it is told to throw a {@link RuntimeException} instead. 8 | */ 9 | public class RecordPathScript implements Script{ 10 | 11 | public static final String EXCEPTION_MESSAGE = "script exception"; 12 | public static final String ATTRIBUTE = "path"; 13 | private static boolean throwException = false; 14 | private int id; 15 | 16 | public RecordPathScript( int id ){ 17 | this.id = id; 18 | } 19 | 20 | @Override 21 | public void execute( Environment environment ){ 22 | if( throwException ){ 23 | throw new RuntimeException( EXCEPTION_MESSAGE ); 24 | } 25 | String path = (String)environment.getAttribute( ATTRIBUTE ); 26 | if( path == null ){ 27 | path = "" + id; 28 | } 29 | else{ 30 | path = path + "," + id; 31 | } 32 | environment.setAttribute( ATTRIBUTE, path ); 33 | } 34 | 35 | public static void startThrowingException(){ 36 | throwException = true; 37 | } 38 | 39 | public static void stopThrowingException(){ 40 | throwException = false; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/error/ExecutionErrorServiceImpl.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.error; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Service; 6 | import org.springframework.transaction.annotation.Transactional; 7 | 8 | import ee.telekom.workflow.util.ExceptionUtil; 9 | 10 | @Service 11 | @Transactional 12 | public class ExecutionErrorServiceImpl implements ExecutionErrorService{ 13 | 14 | @Autowired 15 | private ExecutionErrorDao dao; 16 | 17 | @Override 18 | public void handleError( long woinRefNum, Long woitRefNum, Exception exception ){ 19 | ExecutionError error = new ExecutionError(); 20 | error.setWoinRefNum( woinRefNum ); 21 | error.setWoitRefNum( woitRefNum ); 22 | String errorText = StringUtils.abbreviate( ExceptionUtil.getErrorText( exception ), 500 ); 23 | error.setErrorText( StringUtils.isNotBlank( errorText ) ? errorText : "-" ); 24 | error.setErrorDetails( ExceptionUtil.getErrorDetails( exception ) ); 25 | dao.create( error ); 26 | } 27 | 28 | @Override 29 | public ExecutionError findByWoinRefNum( long woinRefNum ){ 30 | return dao.findByWoinRefNum( woinRefNum ); 31 | } 32 | 33 | @Override 34 | public void delete( long refNum ){ 35 | dao.delete( refNum ); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/console/model/WorkItemStateModel.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console.model; 2 | 3 | import java.io.Serializable; 4 | import java.lang.reflect.InvocationTargetException; 5 | import java.util.Date; 6 | 7 | import org.apache.commons.beanutils.BeanUtils; 8 | 9 | import ee.telekom.workflow.facade.model.WorkItemState; 10 | import ee.telekom.workflow.facade.util.DateUtil; 11 | 12 | public class WorkItemStateModel extends WorkItemState implements Serializable{ 13 | 14 | private static final long serialVersionUID = 1L; 15 | 16 | public static WorkItemStateModel create( WorkItemState woit ){ 17 | WorkItemStateModel model = new WorkItemStateModel(); 18 | try{ 19 | BeanUtils.copyProperties( model, woit ); 20 | } 21 | catch( IllegalAccessException | InvocationTargetException e ){ 22 | throw new RuntimeException( "Error creating model", e ); 23 | } 24 | return model; 25 | } 26 | 27 | public String getDueDateText(){ 28 | return DateUtil.formatDate( getDueDate() ); 29 | } 30 | 31 | public String getDateCreatedText(){ 32 | return DateUtil.formatDate( getDateCreated() ); 33 | } 34 | 35 | public String getDateUpdatedText(){ 36 | return DateUtil.formatDate( getDateUpdated() ); 37 | } 38 | 39 | public boolean isDueDateInFuture(){ 40 | return getDueDate().after( new Date() ); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /telekom-workflow-example/conf/default/server.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/DslVariable.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface DslVariable extends DslExpression{ 12 | 13 | /** 14 | * Store the given constant value or expression result into the environment under the variable name from the previous node: 15 | * .variable( "name" ).value( 1, "Heli Kopter" ) 16 | *

      17 | * NB! There is a Gotcha here: DSL parse time vs. workflow instance run time. All the java objects (for example new Date()) are created 18 | * at the DSL parse time (server startup) vs. all the EL expressions (for example "${NOW}") are evaluated at the runtime when 19 | * this workflow node is processed. So when you are doing .variable( "name" ).value( 1, new Date() ) then you are 20 | * actually getting the server startup date value there, not the runtime moment, when this instance node 1 was processed. So you 21 | * should use only constant values (like strings, numbers, enums etc.) as java objects, and EL expressions for creating runtime 22 | * dynamic objects. 23 | * 24 | * @param id node id 25 | * @param value variable value (any java object (only suitable for constants, see NB!) or "${EL_EXPRESSION}") 26 | */ 27 | Level value( int id, Object value ); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/api/DslBranchBlock.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.api; 2 | 3 | /** 4 | * DSL for workflow definitions. 5 | * 6 | * @author Erko Hansar 7 | * @author Christian Klock 8 | * 9 | * @see WorkflowDefinition 10 | */ 11 | public interface DslBranchBlock extends DslBlock>{ 12 | 13 | /** 14 | * Used inside split branches to cancel all other ongoing branches in this block, but the calling branch continues with it's normal operations. 15 | * 16 | * @param id node id 17 | */ 18 | DslBranchBlock escalate( int id ); 19 | 20 | /** 21 | * Add a branch (parallel execution flow) into the active split. 22 | */ 23 | DslBranchBlock branch(); 24 | 25 | /** 26 | * Add a conditional branch (parallel execution flow) into the active split. Executed only if the condition evaluates to true. 27 | * 28 | * @param condition expression language condition ("EL_EXPRESSION") 29 | */ 30 | DslBranchBlock branch( String condition ); 31 | 32 | /** 33 | * Block end tag, listens for the FIRST arriving branch, immediately cancels all the other ongoing branches in this block and continues execution 34 | * from after the block. 35 | */ 36 | Level joinFirst(); 37 | 38 | /** 39 | * Block end tag, listens until ALL started branches have arrived and then continues execution from after the block. 40 | */ 41 | Level joinAll(); 42 | 43 | } 44 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/GraphWorkItem.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | import java.util.Date; 4 | import java.util.Map; 5 | 6 | import ee.telekom.workflow.api.AutoRecovery; 7 | 8 | /** 9 | * When a {@link Node} execution does not immediately return a result it may 10 | * entitle an external system to perform some actions asynchronously. The action 11 | * to be done is described by a work item (e.g. wait for a timer or an incoming 12 | * signal, call a method on a bean or ask a human to perform a task). 13 | *

      14 | * Another way of describing a {@link GraphWorkItem} is: A work item is a handle/reference 15 | * to an uncompleted node execution in order to complete it at some future point in time. 16 | */ 17 | public interface GraphWorkItem{ 18 | 19 | Long getExternalId(); 20 | 21 | Long getExternalGraphInstanceId(); 22 | 23 | Token getToken(); 24 | 25 | String getSignal(); 26 | 27 | Date getDueDate(); 28 | 29 | String getBean(); 30 | 31 | String getMethod(); 32 | 33 | String getRole(); 34 | 35 | String getUser(); 36 | 37 | Object[] getTaskArguments(); 38 | 39 | Map getHumanTaskArguments(); 40 | 41 | Object getResult(); 42 | 43 | WorkItemStatus getStatus(); 44 | 45 | void setStatus( WorkItemStatus status ); 46 | 47 | void setResult( Object result ); 48 | 49 | void setAutoRecovery( AutoRecovery autoRecovery); 50 | 51 | AutoRecovery autoRecovery(); 52 | 53 | } 54 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/resources/application.properties: -------------------------------------------------------------------------------- 1 | database.workflowengine.driver=org.h2.Driver 2 | database.workflowengine.url=jdbc:h2:mem:engine;INIT=CREATE SCHEMA IF NOT EXISTS ENGINE;MODE=PostgreSQL 3 | database.workflowengine.username=engine 4 | database.workflowengine.password=engine 5 | database.workflowengine.schema= 6 | 7 | workflowengine.cluster.hazelcast.name= 8 | workflowengine.cluster.name=main 9 | workflowengine.cluster.multicast.group= 10 | workflowengine.cluster.multicast.port= 11 | workflowengine.cluster.multicast.ttl= 12 | workflowengine.node.name= 13 | workflowengine.heartbeat.intervalSeconds=60 14 | workflowengine.heartbeat.maximumPauseSeconds=600 15 | workflowengine.maximumNodeAssignementTimeSeconds=15 16 | workflowengine.workItemExecutionTimeWarnSeconds=3600 17 | workflowengine.producer.intervalSeconds=10 18 | workflowengine.consumer.threads=8 19 | workflowengine.pluginApplicationContextFile= 20 | workflowengine.developmentMode=false 21 | workflowengine.environment=TEST 22 | workflowengine.exception.mail.notification.enabled=false 23 | workflowengine.exception.mail.notification.intervalMinutes=15 24 | workflowengine.exception.mail.environment= 25 | workflowengine.exception.mail.host= 26 | workflowengine.exception.mail.port= 27 | workflowengine.exception.mail.username= 28 | workflowengine.exception.mail.password= 29 | workflowengine.exception.mail.from= 30 | workflowengine.exception.mail.recipients= 31 | workflowengine.console.mapping.prefix= 32 | workflowengine.embeddedNavigationMode=false 33 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/input/MapMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.input; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | import ee.telekom.workflow.graph.GraphInstance; 7 | 8 | /** 9 | * InputMapping that evaluates to a Map. The class is mainly intended to created argument maps for human task activities. 10 | */ 11 | public class MapMapping implements InputMapping>{ 12 | 13 | private Map> entryMappings; 14 | 15 | public MapMapping(){ 16 | this( new HashMap>() ); 17 | } 18 | 19 | public MapMapping( Map> entryMappings ){ 20 | this.entryMappings = entryMappings; 21 | } 22 | 23 | public Map> getEntryMappings(){ 24 | return entryMappings; 25 | } 26 | 27 | public void addEntryMapping( String name, InputMapping inputMapping ){ 28 | entryMappings.put( name, inputMapping ); 29 | } 30 | 31 | @Override 32 | public Map evaluate( GraphInstance instance ){ 33 | if( entryMappings == null ){ 34 | return null; 35 | } 36 | Map map = new HashMap<>(); 37 | for( Map.Entry> entry : entryMappings.entrySet() ){ 38 | map.put( entry.getKey(), entry.getValue().evaluate( instance ) ); 39 | } 40 | return map; 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/resources/workflow-engine-jmx.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /telekom-workflow-example/src/main/java/ee/telekom/workflow/example/security/DummyAuthenticationProvider.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.example.security; 2 | 3 | import java.util.Arrays; 4 | import java.util.Collection; 5 | 6 | import org.springframework.security.authentication.AuthenticationProvider; 7 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 8 | import org.springframework.security.core.Authentication; 9 | import org.springframework.security.core.AuthenticationException; 10 | import org.springframework.security.core.GrantedAuthority; 11 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 12 | import org.springframework.stereotype.Component; 13 | 14 | @Component("webConsoleAuthenticationProvider") 15 | public class DummyAuthenticationProvider implements AuthenticationProvider{ 16 | 17 | @Override 18 | public Authentication authenticate( Authentication authentication ) throws AuthenticationException{ 19 | return new UsernamePasswordAuthenticationToken( authentication.getName(), authentication.getCredentials().toString(), getGrantedAuthorities() ); 20 | } 21 | 22 | @Override 23 | public boolean supports( Class authentication ){ 24 | return authentication.equals( UsernamePasswordAuthenticationToken.class ); 25 | } 26 | 27 | private Collection getGrantedAuthorities(){ 28 | return Arrays.asList( new GrantedAuthority[]{new SimpleGrantedAuthority( "ROLE_TWE_ADMIN" )} ); 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/core/GraphValidatorTest.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.core; 2 | 3 | import org.junit.Assert; 4 | import org.junit.Test; 5 | 6 | import ee.telekom.workflow.graph.Graph; 7 | import ee.telekom.workflow.graph.GraphFactory; 8 | import ee.telekom.workflow.graph.GraphValidator; 9 | 10 | public class GraphValidatorTest{ 11 | 12 | @Test 13 | public void test_no_errors(){ 14 | assertValidation( GraphFactory.INSTANCE.sequence_one(), 0 ); 15 | assertValidation( GraphFactory.INSTANCE.sequence_two(), 0 ); 16 | assertValidation( GraphFactory.INSTANCE.exclusivechoice_two(), 0 ); 17 | assertValidation( GraphFactory.INSTANCE.cancelling_discriminator_and_nested(), 0 ); 18 | assertValidation( GraphFactory.INSTANCE.loop_cancelling_discriminator_twice( 1 ), 0 ); 19 | } 20 | 21 | @Test 22 | public void test_with_errors(){ 23 | assertValidation( GraphFactory.INSTANCE.error_no_start_node(), 1 ); 24 | assertValidation( GraphFactory.INSTANCE.error_exclusivechoice_two(), 1 ); 25 | assertValidation( GraphFactory.INSTANCE.error_cancelling_discriminator_two_pre_post(), 1 ); 26 | assertValidation( GraphFactory.INSTANCE.error_reserved_variable_name(), 2 ); 27 | } 28 | 29 | private void assertValidation( Graph graph, int errorCount ){ 30 | GraphValidator validator = new GraphValidatorImpl(); 31 | Assert.assertEquals( errorCount, validator.validate( graph ).size() ); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/marshall/GraphInstanceRepository.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.marshall; 2 | 3 | import ee.telekom.workflow.core.workflowinstance.WorkflowInstance; 4 | import ee.telekom.workflow.core.workflowinstance.WorkflowInstanceStatus; 5 | import ee.telekom.workflow.core.workitem.WorkItem; 6 | import ee.telekom.workflow.graph.GraphInstance; 7 | import ee.telekom.workflow.graph.GraphWorkItem; 8 | 9 | /** 10 | * Provides a load and save service to persist a {@link GraphInstance}. 11 | *

      12 | * The repository converts between the persistent artifacts ({@link WorkflowInstance} and 13 | * {@link WorkItem}) and the non-persistent artifacts ({@link GraphInstance} and 14 | * {@link GraphWorkItem}). 15 | * 16 | * @author Christian Klock 17 | */ 18 | public interface GraphInstanceRepository{ 19 | 20 | /** 21 | * Loads the {@link GraphInstance} identified by the given workflow instance refNum. 22 | */ 23 | GraphInstance load( long woinRefNum ); 24 | 25 | /** 26 | * Saves the {@link GraphInstance} and therefore updates workflow instance and work item fields. 27 | *

      28 | * If the graph instance execution is completed, updates the workflow instance status to the 29 | * given completeStatus. This way, we can choose between EXECUTED and ABORTED which are 30 | * indistinguishable from the {@link GraphInstance} point of view. 31 | */ 32 | void save( GraphInstance graphInstance, WorkflowInstanceStatus completeStatus ); 33 | 34 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/facade/workitem/WorkItemStateRowMapper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.workitem; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | import ee.telekom.workflow.facade.model.WorkItemState; 7 | import ee.telekom.workflow.util.AbstractRowMapper; 8 | 9 | public class WorkItemStateRowMapper extends AbstractRowMapper{ 10 | 11 | public static final WorkItemStateRowMapper INSTANCE = new WorkItemStateRowMapper(); 12 | 13 | @Override 14 | public WorkItemState mapRow( ResultSet rs, int rowNum ) throws SQLException{ 15 | WorkItemState object = new WorkItemState(); 16 | object.setRefNum( getLong( rs, "ref_num" ) ); 17 | object.setWoinRefNum( getLong( rs, "woin_ref_num" ) ); 18 | object.setTokenId( getInteger( rs, "token_id" ) ); 19 | object.setStatus( getString( rs, "status" ) ); 20 | object.setSignal( getString( rs, "signal" ) ); 21 | object.setDueDate( getDate( rs, "due_date" ) ); 22 | object.setBean( getString( rs, "bean" ) ); 23 | object.setMethod( getString( rs, "method" ) ); 24 | object.setRole( getString( rs, "role" ) ); 25 | object.setUserName( getString( rs, "user_name" ) ); 26 | object.setArguments( getString( rs, "arguments" ) ); 27 | object.setResult( getString( rs, "result" ) ); 28 | object.setDateCreated( getDate( rs, "date_created" ) ); 29 | object.setDateUpdated( getDate( rs, "date_updated" ) ); 30 | return object; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/core/TokenImpl.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.core; 2 | 3 | import ee.telekom.workflow.graph.GraphInstance; 4 | import ee.telekom.workflow.graph.Node; 5 | import ee.telekom.workflow.graph.Token; 6 | 7 | public class TokenImpl implements Token{ 8 | 9 | private int id; 10 | private Node node; 11 | private GraphInstance instance; 12 | private Token parent; 13 | private boolean isActive; 14 | 15 | @Override 16 | public int getId(){ 17 | return id; 18 | } 19 | 20 | public void setId( int id ){ 21 | this.id = id; 22 | } 23 | 24 | @Override 25 | public Node getNode(){ 26 | return node; 27 | } 28 | 29 | @Override 30 | public void setNode( Node node ){ 31 | this.node = node; 32 | } 33 | 34 | @Override 35 | public GraphInstance getInstance(){ 36 | return instance; 37 | } 38 | 39 | public void setInstance( GraphInstance instance ){ 40 | this.instance = instance; 41 | } 42 | 43 | @Override 44 | public Token getParent(){ 45 | return parent; 46 | } 47 | 48 | public void setParent( Token parent ){ 49 | this.parent = parent; 50 | } 51 | 52 | @Override 53 | public boolean isActive(){ 54 | return isActive; 55 | } 56 | 57 | public void setActive( boolean isActive ){ 58 | this.isActive = isActive; 59 | } 60 | 61 | @Override 62 | public void markInactive(){ 63 | setActive( false ); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/gateway/condition/ExpressionLanguageCondition.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway.condition; 2 | 3 | import jakarta.el.ELProcessor; 4 | 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import ee.telekom.workflow.graph.Environment; 8 | import ee.telekom.workflow.graph.GraphInstance; 9 | import ee.telekom.workflow.graph.el.ElUtil; 10 | 11 | /** 12 | * Provides expression language condition evaluation against {@link Environment} variables. 13 | * 14 | * http://docs.oracle.com/javaee/7/api/javax/el/package-summary.html 15 | * 16 | * If the condition uses an unknown variable "foobar" (which has not yet been set in the Environment), an exception will occur: 17 | * "ELResolver cannot handle a null base Object with identifier 'foobar'" 18 | * 19 | * @author Erko Hansar 20 | */ 21 | public class ExpressionLanguageCondition implements Condition{ 22 | 23 | private String condition; 24 | 25 | public ExpressionLanguageCondition( String condition ){ 26 | this.condition = condition; 27 | } 28 | 29 | public String getCondition(){ 30 | return condition; 31 | } 32 | 33 | @Override 34 | public boolean evaluate( GraphInstance instance ){ 35 | boolean result = false; 36 | if( StringUtils.isNotBlank( condition ) ){ 37 | ELProcessor processor = ElUtil.initNewELProcessor( instance.getEnvironment(), instance.getExternalId() ); 38 | result = (boolean)processor.eval( condition ); 39 | } 40 | return result; 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/util/JsonParserUtil.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.util; 2 | 3 | import com.google.gson.JsonElement; 4 | import com.google.gson.JsonNull; 5 | import com.google.gson.JsonObject; 6 | import com.google.gson.JsonParser; 7 | 8 | /** 9 | * Utility to provide NULL safe manual Json parsing operations 10 | */ 11 | public class JsonParserUtil{ 12 | 13 | private static final JsonParser parser = new JsonParser(); 14 | 15 | public static JsonObject parseJson( String body ){ 16 | return parser.parse( body ).getAsJsonObject(); 17 | } 18 | 19 | public static String getAsNullSafeString( JsonObject object, String memberName ){ 20 | if( object != null ){ 21 | JsonElement element = object.get( memberName ); 22 | return element == null || element instanceof JsonNull ? null : element.getAsString(); 23 | } 24 | return null; 25 | } 26 | 27 | public static Integer getAsNullSafeInteger( JsonObject object, String memberName ){ 28 | if( object != null ){ 29 | JsonElement element = object.get( memberName ); 30 | return element == null || element instanceof JsonNull ? null : element.getAsInt(); 31 | } 32 | return null; 33 | } 34 | 35 | public static String toNullSafeJsonString( JsonObject object, String memberName ){ 36 | if( object != null ){ 37 | JsonElement element = object.get( memberName ); 38 | return element != null ? element.toString() : null; 39 | } 40 | return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/activity/ScriptActivity.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.activity; 2 | 3 | import ee.telekom.workflow.graph.Environment; 4 | import ee.telekom.workflow.graph.GraphEngine; 5 | import ee.telekom.workflow.graph.Token; 6 | import ee.telekom.workflow.graph.node.AbstractNode; 7 | 8 | /** 9 | * Activity executing a given {@link Script}. The script is executed synchronously. 10 | */ 11 | public class ScriptActivity extends AbstractNode{ 12 | 13 | private Script script; 14 | 15 | public ScriptActivity( int id, Script script ){ 16 | this( id, null, script ); 17 | } 18 | 19 | public ScriptActivity( int id, String name, Script script ){ 20 | super( id, name ); 21 | this.script = script; 22 | } 23 | 24 | public Script getScript() { 25 | return script; 26 | } 27 | 28 | @Override 29 | public void execute( GraphEngine engine, Token token ){ 30 | script.execute( token.getInstance().getEnvironment() ); 31 | engine.complete( token, null ); 32 | } 33 | 34 | @Override 35 | public void cancel( GraphEngine engine, Token token ){ 36 | // Tokens cannot "wait" at this kind of node since the execution 37 | // is synchronous. Hence, no "cancel" action is required. 38 | } 39 | 40 | @Override 41 | public void store( Environment environment, Object result ){ 42 | // This type of node does not produce a result 43 | } 44 | 45 | public static interface Script{ 46 | void execute( Environment environment ); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/output/MapEntryMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.output; 2 | 3 | import java.util.Map; 4 | 5 | import ee.telekom.workflow.graph.Environment; 6 | 7 | /** 8 | * Given a node execution result which is a Map, this {@link OutputMapping} maps each entry of the execution result 9 | * on an attribute in the {@link Environment}. This {@link OutputMapping} enables to return "multiple values" to the 10 | * {@link Environment}. 11 | *

      12 | * If the result object map does not contain an entry for any given key, then this parameter value is set to NULL. 13 | */ 14 | public class MapEntryMapping implements OutputMapping{ 15 | 16 | private Map mappings; 17 | 18 | public MapEntryMapping( Map mappings ){ 19 | this.mappings = mappings; 20 | } 21 | 22 | public Map getMappings(){ 23 | return mappings; 24 | } 25 | 26 | @Override 27 | public void map( Environment environment, Object result ){ 28 | @SuppressWarnings("unchecked") 29 | Map map = (Map)result; 30 | for( Map.Entry mapping : mappings.entrySet() ){ 31 | String resultKey = mapping.getKey(); 32 | String environmentKey = mapping.getValue(); 33 | if( map.containsKey( resultKey ) ){ 34 | environment.setAttribute( environmentKey, map.get( resultKey ) ); 35 | } 36 | else{ 37 | environment.setAttribute( environmentKey, null ); 38 | } 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/rest/model/WorkflowInstanceRestModel.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.rest.model; 2 | 3 | import java.io.Serializable; 4 | 5 | import ee.telekom.workflow.core.workflowinstance.WorkflowInstanceStatus; 6 | 7 | public class WorkflowInstanceRestModel implements Serializable{ 8 | 9 | private static final long serialVersionUID = 1L; 10 | private long refNum; 11 | private String workflowName; 12 | private Integer workflowVersion; 13 | 14 | private String label1; 15 | private String label2; 16 | 17 | private WorkflowInstanceStatus status; 18 | 19 | // For Spring 20 | public WorkflowInstanceRestModel(){ 21 | } 22 | 23 | public WorkflowInstanceRestModel( long refNum, String workflowName, Integer workflowVersion, String label1, String label2, WorkflowInstanceStatus status ){ 24 | this.refNum = refNum; 25 | this.workflowName = workflowName; 26 | this.workflowVersion = workflowVersion; 27 | this.label1 = label1; 28 | this.label2 = label2; 29 | this.status = status; 30 | } 31 | 32 | public long getRefNum(){ 33 | return refNum; 34 | } 35 | 36 | public String getWorkflowName(){ 37 | return workflowName; 38 | } 39 | 40 | public Integer getWorkflowVersion(){ 41 | return workflowVersion; 42 | } 43 | 44 | public String getLabel1(){ 45 | return label1; 46 | } 47 | 48 | public String getLabel2(){ 49 | return label2; 50 | } 51 | 52 | public WorkflowInstanceStatus getStatus(){ 53 | return status; 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/node/Node.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.node; 2 | 3 | import java.util.Date; 4 | 5 | import ee.telekom.workflow.facade.WorkflowEngineFacade; 6 | 7 | /** 8 | * Encapsulates the state of an engine's instance within the cluster. 9 | *

      10 | * This class is intended for internal usage within this module and should not 11 | * be passed to external clients via the {@link WorkflowEngineFacade}. 12 | * 13 | * @author Christian Klock 14 | */ 15 | public class Node{ 16 | 17 | private Long refNum; 18 | private String nodeName; 19 | private String clusterName; 20 | private NodeStatus status; 21 | private Date heartbeat; 22 | 23 | public Long getRefNum(){ 24 | return refNum; 25 | } 26 | 27 | public void setRefNum( Long refNum ){ 28 | this.refNum = refNum; 29 | } 30 | 31 | public String getNodeName(){ 32 | return nodeName; 33 | } 34 | 35 | public void setNodeName( String nodeName ){ 36 | this.nodeName = nodeName; 37 | } 38 | 39 | public String getClusterName(){ 40 | return clusterName; 41 | } 42 | 43 | public void setClusterName( String clusterName ){ 44 | this.clusterName = clusterName; 45 | } 46 | 47 | public NodeStatus getStatus(){ 48 | return status; 49 | } 50 | 51 | public void setStatus( NodeStatus status ){ 52 | this.status = status; 53 | } 54 | 55 | public Date getHeartbeat(){ 56 | return heartbeat; 57 | } 58 | 59 | public void setHeartbeat( Date heartbeat ){ 60 | this.heartbeat = heartbeat; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/input/ExpressionLanguageMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.input; 2 | 3 | 4 | import jakarta.el.ELProcessor; 5 | 6 | import org.apache.commons.lang3.StringUtils; 7 | 8 | import ee.telekom.workflow.graph.Environment; 9 | import ee.telekom.workflow.graph.GraphInstance; 10 | import ee.telekom.workflow.graph.el.ElUtil; 11 | 12 | /** 13 | * Provides expression language based InputMapping against {@link Environment} variables. 14 | * 15 | * http://docs.oracle.com/javaee/7/api/javax/el/package-summary.html 16 | * 17 | * If the mapping uses an unknown variable "foobar" (which has not yet been set in the Environment), an exception will occur: 18 | * "ELResolver cannot handle a null base Object with identifier 'foobar'" 19 | * 20 | * @author Erko Hansar 21 | */ 22 | public class ExpressionLanguageMapping implements InputMapping{ 23 | 24 | private String expression; 25 | 26 | public ExpressionLanguageMapping( String expression ){ 27 | this.expression = expression; 28 | } 29 | 30 | public String getExpression(){ 31 | return expression; 32 | } 33 | 34 | @Override 35 | @SuppressWarnings("unchecked") 36 | public T evaluate( GraphInstance instance ){ 37 | if( StringUtils.isNotBlank( expression ) ){ 38 | ELProcessor processor = ElUtil.initNewELProcessor( instance.getEnvironment(), instance.getExternalId() ); 39 | Object expressionResult = processor.eval( ElUtil.removeBrackets( expression ) ); 40 | return (T)expressionResult; 41 | } 42 | return null; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/node/gateway/_06_MultipleChoiceTest.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import org.junit.Test; 4 | 5 | import ee.telekom.workflow.graph.AbstractGraphTest; 6 | import ee.telekom.workflow.graph.GraphFactory; 7 | 8 | public class _06_MultipleChoiceTest extends AbstractGraphTest { 9 | 10 | @Test 11 | public void one() { 12 | assertConditionalExecution(GraphFactory.INSTANCE.multiplechoice_one(), 13 | GraphFactory.VALUE1, "2"); 14 | 15 | assertConditionalExecution(GraphFactory.INSTANCE.multiplechoice_one(), 16 | null, null); 17 | } 18 | 19 | @Test 20 | public void two() { 21 | assertConditionalExecution(GraphFactory.INSTANCE.multiplechoice_two(), 22 | GraphFactory.VALUE1, "2"); 23 | 24 | assertConditionalExecution(GraphFactory.INSTANCE.multiplechoice_two(), 25 | GraphFactory.VALUE2, "3"); 26 | 27 | assertConditionalExecution(GraphFactory.INSTANCE.multiplechoice_two(), 28 | null, null); 29 | } 30 | 31 | @Test 32 | public void defaultTest() { 33 | assertConditionalExecution( 34 | GraphFactory.INSTANCE.multiplechoice_default(), null, "2"); 35 | } 36 | 37 | @Test 38 | public void one_default() { 39 | assertConditionalExecution( 40 | GraphFactory.INSTANCE.multiplechoice_one_default(), 41 | GraphFactory.VALUE1, "2,3"); 42 | 43 | assertConditionalExecution( 44 | GraphFactory.INSTANCE.multiplechoice_one_default(), null, "3"); 45 | } 46 | 47 | @Test 48 | public void twoConditionsTrue() { 49 | assertConditionalExecution( 50 | GraphFactory.INSTANCE.multiplechoice_twoConditionsTrue(), 51 | GraphFactory.VALUE1, "2,3"); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/error/ExecutionError.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.error; 2 | 3 | import ee.telekom.workflow.facade.WorkflowEngineFacade; 4 | 5 | /** 6 | * Encapsulates information on an error when processing consuming a work unit. 7 | *

      8 | * This class is intended for internal usage within this module and should not 9 | * be passed to external clients via the {@link WorkflowEngineFacade}. 10 | * 11 | * @author Christian Klock 12 | */ 13 | public class ExecutionError{ 14 | 15 | private Long refNum; 16 | 17 | private Long woinRefNum; 18 | private Long woitRefNum; 19 | private String errorText; 20 | private String errorDetails; 21 | 22 | public Long getRefNum(){ 23 | return refNum; 24 | } 25 | 26 | public void setRefNum( Long refNum ){ 27 | this.refNum = refNum; 28 | } 29 | 30 | public Long getWoinRefNum(){ 31 | return woinRefNum; 32 | } 33 | 34 | public void setWoinRefNum( Long woinRefNum ){ 35 | this.woinRefNum = woinRefNum; 36 | } 37 | 38 | public Long getWoitRefNum(){ 39 | return woitRefNum; 40 | } 41 | 42 | public void setWoitRefNum( Long woitRefNum ){ 43 | this.woitRefNum = woitRefNum; 44 | } 45 | 46 | public String getErrorText(){ 47 | return errorText; 48 | } 49 | 50 | public void setErrorText( String errorText ){ 51 | this.errorText = errorText; 52 | } 53 | 54 | public String getErrorDetails(){ 55 | return errorDetails; 56 | } 57 | 58 | public void setErrorDetails( String errorDetails ){ 59 | this.errorDetails = errorDetails; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/facade/workflowinstance/WorkflowInstanceStateRowMapper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.workflowinstance; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | import ee.telekom.workflow.facade.model.WorkflowInstanceState; 7 | import ee.telekom.workflow.util.AbstractRowMapper; 8 | 9 | public class WorkflowInstanceStateRowMapper extends AbstractRowMapper{ 10 | 11 | public static final WorkflowInstanceStateRowMapper INSTANCE = new WorkflowInstanceStateRowMapper(); 12 | 13 | @Override 14 | public WorkflowInstanceState mapRow( ResultSet rs, int rowNum ) throws SQLException{ 15 | WorkflowInstanceState object = new WorkflowInstanceState(); 16 | object.setRefNum( getLong( rs, "ref_num" ) ); 17 | object.setWorkflowName( getString( rs, "workflow_name" ) ); 18 | object.setWorkflowVersion( getInteger( rs, "workflow_version" ) ); 19 | object.setAttributes( getString( rs, "attributes" ) ); 20 | object.setState( getString( rs, "state" ) ); 21 | object.setHistory( getString( rs, "history" ) ); 22 | object.setLabel1( getString( rs, "label1" ) ); 23 | object.setLabel2( getString( rs, "label2" ) ); 24 | object.setClusterName( getString( rs, "cluster_name" ) ); 25 | object.setNodeName( getString( rs, "node_name" ) ); 26 | object.setStatus( getString( rs, "status" ) ); 27 | object.setLocked( getBoolean( rs, "locked" ) ); 28 | object.setDateCreated( getDate( rs, "date_created" ) ); 29 | object.setDateUpdated( getDate( rs, "date_updated" ) ); 30 | return object; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/jsp-twe/console/status.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> 2 | <%@ include file="../header.jspf" %> 3 | 4 | 5 |

      6 |
      7 | 8 |
      9 |
      10 |

      [

      11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
      27 |
      28 |
      29 |
      30 |
      31 |
      32 |
      33 | 34 | <%@ include file="../footer.jspf" %> -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/console/form/CreateWorkflowInstanceForm.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console.form; 2 | 3 | import java.io.Serializable; 4 | 5 | public class CreateWorkflowInstanceForm implements Serializable { 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | private Long refNum; 10 | private String workflowName; 11 | private String workflowVersion; 12 | private String arguments; 13 | private String label1; 14 | private String label2; 15 | 16 | public Long getRefNum(){ 17 | return refNum; 18 | } 19 | 20 | public void setRefNum( Long refNum ){ 21 | this.refNum = refNum; 22 | } 23 | 24 | public String getWorkflowName(){ 25 | return workflowName; 26 | } 27 | 28 | public void setWorkflowName( String workflowName ){ 29 | this.workflowName = workflowName; 30 | } 31 | 32 | public String getWorkflowVersion(){ 33 | return workflowVersion; 34 | } 35 | 36 | public void setWorkflowVersion( String workflowVersion ){ 37 | this.workflowVersion = workflowVersion; 38 | } 39 | 40 | public String getArguments(){ 41 | return arguments; 42 | } 43 | 44 | public void setArguments( String arguments ){ 45 | this.arguments = arguments; 46 | } 47 | 48 | public String getLabel1(){ 49 | return label1; 50 | } 51 | 52 | public void setLabel1( String label1 ){ 53 | this.label1 = label1; 54 | } 55 | 56 | public String getLabel2(){ 57 | return label2; 58 | } 59 | 60 | public void setLabel2( String label2 ){ 61 | this.label2 = label2; 62 | } 63 | 64 | } 65 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/executor/producer/WorkProducerServiceImpl.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.executor.producer; 2 | 3 | import java.lang.invoke.MethodHandles; 4 | import java.util.List; 5 | 6 | import org.apache.commons.lang3.SerializationUtils; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.stereotype.Service; 11 | import org.springframework.transaction.annotation.Transactional; 12 | 13 | import ee.telekom.workflow.core.workunit.WorkUnit; 14 | import ee.telekom.workflow.core.workunit.WorkUnitService; 15 | import ee.telekom.workflow.executor.queue.WorkQueue; 16 | 17 | @Service 18 | @Transactional 19 | public class WorkProducerServiceImpl implements WorkProducerService{ 20 | 21 | private static final Logger log = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() ); 22 | 23 | @Autowired 24 | private WorkUnitService workUnitService; 25 | @Autowired 26 | private WorkQueue queue; 27 | 28 | @Override 29 | public void produceWork( List unprocessedWorkUnits, int maxBatchSize ) throws InterruptedException{ 30 | List batchOfWorkUnits = unprocessedWorkUnits.subList(0, Math.min(maxBatchSize, unprocessedWorkUnits.size())); 31 | if( batchOfWorkUnits.size() > 0 ){ 32 | workUnitService.lock( batchOfWorkUnits ); 33 | for( WorkUnit wu : batchOfWorkUnits ){ 34 | log.info( "Adding '{}' to queue", wu ); 35 | queue.put( SerializationUtils.clone( wu ) ); 36 | } 37 | batchOfWorkUnits.clear(); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /telekom-workflow-example/src/main/java/ee/telekom/workflow/example/service/CustomerService.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.example.service; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Date; 5 | import java.util.Map; 6 | 7 | /** 8 | * An example business logic service that will allow your workflows to integrate with your backend systems. Normally 9 | * the contained methods would be located in multiple different services (like billing service, configuration service, 10 | * messaging service, order service etc.) but they are all located in this single service to keep things simple for 11 | * the demo app. 12 | * 13 | * @author Erko Hansar 14 | */ 15 | public interface CustomerService{ 16 | 17 | ///// CUSTOMER SERVICES ///// 18 | 19 | String getCustomerName( String customerId ); 20 | 21 | String getCustomerStatus( String customerId ); 22 | 23 | String getAccountManager( String customerId ); 24 | 25 | Map getCustomerVariableMap( String customerId ); 26 | 27 | ///// BILLING SERVICES ///// 28 | 29 | BigDecimal getCustomerBalance( String customerId ); 30 | 31 | void createPaymentSchedule( String customerId, BigDecimal balance ); 32 | 33 | void debtCollected( String customerId ); 34 | 35 | void writeOffDebt( String customerId ); 36 | 37 | ///// MESSAGING SERVICES ///// 38 | 39 | boolean sendDebtWarning( String customerId, BigDecimal customerBalance, String warningType ); 40 | 41 | ///// CONFIGURATION SERVICES ///// 42 | 43 | Date getSuspendTimeAfterWarning(); 44 | 45 | ///// ORDER SERVICES ///// 46 | 47 | String suspendCustomer( String customerId ); 48 | 49 | String getOrderStatus( String orderId ); 50 | 51 | } 52 | -------------------------------------------------------------------------------- /telekom-workflow-example/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ${logs.dir.resolved}/${log.file.resolved} 10 | 11 | ${logs.dir.resolved}/${log.file.resolved}.%d{yyyy-MM-dd} 12 | ${logs.maxhistory:-7} 13 | 14 | 15 | UTF-8 16 | %d{HH:mm:ss.SSS}||%-5level|%logger{40}|%X{workunit}%X{requestmdc}|%msg|%n 17 | 18 | 19 | 20 | 21 | 22 | 500 23 | 0 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/StatisticsLoggingAspect.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | import java.lang.invoke.MethodHandles; 4 | 5 | import org.aspectj.lang.ProceedingJoinPoint; 6 | import org.aspectj.lang.annotation.Around; 7 | import org.aspectj.lang.annotation.Aspect; 8 | import org.aspectj.lang.annotation.Pointcut; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | /** 13 | * Writes a DEBUG log entry after every ee.telekom.workflow package @Service class public method call. 14 | * The row contains the elapsed milliseconds and an exception message if thrown. 15 | * 16 | * @author Erko Hansar 17 | */ 18 | @Aspect 19 | public class StatisticsLoggingAspect{ 20 | 21 | private static final Logger log = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() ); 22 | 23 | @Pointcut("execution(public * ee.telekom.workflow..*(..))") 24 | public void publicWorkflowMethod(){ 25 | } 26 | 27 | @Around("publicWorkflowMethod() && @within(org.springframework.stereotype.Service)") 28 | public Object aroundServiceMethod( ProceedingJoinPoint pjp ) throws Throwable{ 29 | long start = System.currentTimeMillis(); 30 | Throwable error = null; 31 | try{ 32 | return pjp.proceed(); 33 | } 34 | catch( Throwable t ){ 35 | error = t; 36 | throw t; 37 | } 38 | finally{ 39 | if( log.isDebugEnabled() ){ 40 | long elapsed = System.currentTimeMillis() - start; 41 | log.debug( pjp.toShortString() + " took " + elapsed + " ms" + (error != null ? ", exception: " + error : "") ); 42 | } 43 | } 44 | 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/console/helper/MessageHelper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.console.helper; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.context.MessageSource; 5 | import org.springframework.context.i18n.LocaleContextHolder; 6 | import org.springframework.stereotype.Service; 7 | 8 | import ee.telekom.workflow.core.workflowinstance.WorkflowInstanceStatus; 9 | import ee.telekom.workflow.facade.model.WorkflowInstanceFacadeStatus; 10 | import ee.telekom.workflow.facade.util.StatusUtil; 11 | 12 | @Service 13 | public class MessageHelper{ 14 | 15 | @Autowired 16 | private MessageSource messageSource; 17 | 18 | public String getStatusText( WorkflowInstanceStatus status ){ 19 | WorkflowInstanceFacadeStatus facadeStatus = StatusUtil.toFacade( status ); 20 | String message = "workflowinstance.status.facadedetailed." + facadeStatus.name(); 21 | Object[] args = {status}; 22 | return messageSource.getMessage( message, args, LocaleContextHolder.getLocale() ); 23 | } 24 | 25 | public String getHasActiveHumanTaskText( boolean hasActiveHumanTask ){ 26 | String message = "workflow.instances.humantask." + hasActiveHumanTask; 27 | return messageSource.getMessage( message, null, LocaleContextHolder.getLocale() ); 28 | } 29 | 30 | public String getVersionText( Integer version ){ 31 | if( version != null ){ 32 | return version.toString(); 33 | } 34 | else{ 35 | String message = "workflowinstance.workflowversion.latest"; 36 | return messageSource.getMessage( message, null, LocaleContextHolder.getLocale() ); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/workflowinstance/WorkflowInstanceRowMapper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.workflowinstance; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | import ee.telekom.workflow.util.AbstractRowMapper; 7 | 8 | /** 9 | * Row mapper for {@link WorkflowInstance}s that maps all database fields except the 10 | * ones that are not used by the internal parts of the engine (date_created, created_by, 11 | * date_last_updated, last_updated_by). 12 | * 13 | * @author Christian Klock 14 | */ 15 | public class WorkflowInstanceRowMapper extends AbstractRowMapper{ 16 | 17 | public static final WorkflowInstanceRowMapper INSTANCE = new WorkflowInstanceRowMapper(); 18 | 19 | @Override 20 | public WorkflowInstance mapRow( ResultSet rs, int rowNum ) throws SQLException{ 21 | WorkflowInstance object = new WorkflowInstance(); 22 | object.setRefNum( getLong( rs, "ref_num" ) ); 23 | object.setWorkflowName( getString( rs, "workflow_name" ) ); 24 | object.setWorkflowVersion( getInteger( rs, "workflow_version" ) ); 25 | object.setAttributes( getString( rs, "attributes" ) ); 26 | object.setState( getString( rs, "state" ) ); 27 | object.setHistory( getString( rs, "history" ) ); 28 | object.setLabel1( getString( rs, "label1" ) ); 29 | object.setLabel2( getString( rs, "label2" ) ); 30 | object.setClusterName( getString( rs, "cluster_name" ) ); 31 | object.setNodeName( getString( rs, "node_name" ) ); 32 | object.setStatus( getWorkflowInstanceStatus( rs, "status" ) ); 33 | object.setLocked( getBoolean( rs, "locked" ) ); 34 | return object; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/workitem/WorkItemRowMapper.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.workitem; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.SQLException; 5 | 6 | import ee.telekom.workflow.api.AutoRecovery; 7 | import ee.telekom.workflow.util.AbstractRowMapper; 8 | 9 | /** 10 | * Row mapper for {@link WorkItem}s that maps all database fields except the 11 | * ones that are not used by the internal parts of the engine (date_created, created_by, 12 | * date_last_updated, last_updated_by). 13 | * 14 | * @author Christian Klock 15 | */ 16 | public class WorkItemRowMapper extends AbstractRowMapper{ 17 | 18 | public static final WorkItemRowMapper INSTANCE = new WorkItemRowMapper(); 19 | 20 | @Override 21 | public WorkItem mapRow( ResultSet rs, int rowNum ) throws SQLException{ 22 | WorkItem object = new WorkItem(); 23 | object.setRefNum( getLong( rs, "ref_num" ) ); 24 | object.setWoinRefNum( getLong( rs, "woin_ref_num" ) ); 25 | object.setTokenId( getInteger( rs, "token_id" ) ); 26 | object.setStatus( getWorkItemStatus( rs, "status" ) ); 27 | object.setSignal( getString( rs, "signal" ) ); 28 | object.setDueDate( getDate( rs, "due_date" ) ); 29 | object.setBean( getString( rs, "bean" ) ); 30 | object.setMethod( getString( rs, "method" ) ); 31 | object.setRole( getString( rs, "role" ) ); 32 | object.setUserName( getString( rs, "user_name" ) ); 33 | object.setArguments( getString( rs, "arguments" ) ); 34 | object.setResult( getString( rs, "result" ) ); 35 | object.setAutoRecovery( AutoRecovery.of(rs.getBoolean("auto_recovery")) ); 36 | return object; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/facade/model/CreateWorkflowInstance.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.model; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Model object that contains necessary information to create a new workflow instance. 7 | * 8 | * @author Christian Klock 9 | */ 10 | public class CreateWorkflowInstance{ 11 | 12 | private Long refNum; 13 | private String workflowName; 14 | private Integer workflowVersion; 15 | private String label1; 16 | private String label2; 17 | private Map arguments; 18 | 19 | public Long getRefNum(){ 20 | return refNum; 21 | } 22 | 23 | public void setRefNum( Long refNum ){ 24 | this.refNum = refNum; 25 | } 26 | 27 | public String getWorkflowName(){ 28 | return workflowName; 29 | } 30 | 31 | public void setWorkflowName( String workflowName ){ 32 | this.workflowName = workflowName; 33 | } 34 | 35 | public Integer getWorkflowVersion(){ 36 | return workflowVersion; 37 | } 38 | 39 | public void setWorkflowVersion( Integer workflowVersion ){ 40 | this.workflowVersion = workflowVersion; 41 | } 42 | 43 | public String getLabel1(){ 44 | return label1; 45 | } 46 | 47 | public void setLabel1( String label1 ){ 48 | this.label1 = label1; 49 | } 50 | 51 | public String getLabel2(){ 52 | return label2; 53 | } 54 | 55 | public void setLabel2( String label2 ){ 56 | this.label2 = label2; 57 | } 58 | 59 | public Map getArguments(){ 60 | return arguments; 61 | } 62 | 63 | public void setArguments( Map arguments ){ 64 | this.arguments = arguments; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/input/ExpressionMapping.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.input; 2 | 3 | import ee.telekom.workflow.graph.GraphInstance; 4 | import ee.telekom.workflow.graph.node.event.CatchTimer; 5 | import ee.telekom.workflow.graph.node.expression.Expression; 6 | 7 | /** 8 | * InputMapping for a value evaluated by the execution of the given expression. 9 | *

      10 | * NB! This is a home-built Expression support class (can be used by implementing the Expression interface), it doesn't have anything to 11 | * do with the Expression Language support (@see ExpressionLanguageMapping). At the time of writing, this InputMapping is actually not 12 | * usable via the workflow engine API (DSL). 13 | *

      14 | * A possible usage of this class is to dynamically evaluate the delay time of a 15 | * {@link CatchTimer} event node with custom logic based on {@link GraphInstance} 16 | * attribute's (e.g. a client id). 17 | */ 18 | public class ExpressionMapping implements InputMapping{ 19 | 20 | private Expression expression; 21 | private ArrayMapping argumentMapping; 22 | 23 | public ExpressionMapping( Expression expression, InputMapping... argumentMappings ){ 24 | this.expression = expression; 25 | this.argumentMapping = new ArrayMapping( argumentMappings ); 26 | } 27 | 28 | public Expression getExpression(){ 29 | return expression; 30 | } 31 | 32 | public ArrayMapping getArgumentMapping(){ 33 | return argumentMapping; 34 | } 35 | 36 | @Override 37 | public T evaluate( GraphInstance instance ){ 38 | Object[] arguments = argumentMapping.evaluate( instance ); 39 | return expression.execute( arguments ); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/rest/model/HumanTaskModel.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.rest.model; 2 | 3 | import java.io.Serializable; 4 | 5 | import ee.telekom.workflow.graph.WorkItemStatus; 6 | 7 | public class HumanTaskModel implements Serializable{ 8 | 9 | private static final long serialVersionUID = 1L; 10 | private long refNum; 11 | private long woinRefNum; 12 | 13 | private int tokenId; 14 | private WorkItemStatus status; 15 | 16 | private String role; 17 | private String user; 18 | 19 | private String arguments; 20 | private String result; 21 | 22 | public HumanTaskModel(){ 23 | } 24 | 25 | public HumanTaskModel( long refNum, long woinRefNum, int tokenId, WorkItemStatus status, String role, String userName, String arguments, String result ){ 26 | this.refNum = refNum; 27 | this.woinRefNum = woinRefNum; 28 | this.tokenId = tokenId; 29 | this.status = status; 30 | this.role = role; 31 | this.user = userName; 32 | this.arguments = arguments; 33 | this.result = result; 34 | } 35 | 36 | public long getRefNum(){ 37 | return refNum; 38 | } 39 | 40 | public long getWoinRefNum(){ 41 | return woinRefNum; 42 | } 43 | 44 | public int getTokenId(){ 45 | return tokenId; 46 | } 47 | 48 | public WorkItemStatus getStatus(){ 49 | return status; 50 | } 51 | 52 | public String getRole(){ 53 | return role; 54 | } 55 | 56 | public String getUser(){ 57 | return user; 58 | } 59 | 60 | public String getArguments(){ 61 | return arguments; 62 | } 63 | 64 | public String getResult(){ 65 | return result; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/GraphRepository.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | import java.util.Set; 4 | 5 | /** 6 | * The {@link GraphRepository} is a container of {@link Graph} definitions. 7 | */ 8 | public interface GraphRepository{ 9 | 10 | /** 11 | * Returns the {@link Graph} with the given name and the given version, 12 | * or the latest graph with the given name if no version is null, 13 | * or null if no such graph is found.
      14 | * The latest graph is the graph with the greatest version number. 15 | * 16 | * @param name 17 | * the graph name 18 | * @param version 19 | * the graph version 20 | * @return the {@link Graph} with the given name and the given version, or 21 | * null if no suitable graph is found. 22 | */ 23 | Graph getGraph( String name, Integer version ); 24 | 25 | /** 26 | * Returns all graphs with the given name ordered with decreasing version 27 | * number. 28 | * 29 | * @param name 30 | * the graph name 31 | * @return all graphs with the given name ordered with decreasing version 32 | * number. 33 | */ 34 | Set getGraphs( String name ); 35 | 36 | /** 37 | * Returns all graphs accessible via this repository. 38 | * 39 | * @return all graphs accessible via this repository 40 | */ 41 | Set getGraphs(); 42 | 43 | /** 44 | * Adds a graph to the repository and overwrites any previously defined 45 | * graph with identical name and version. 46 | * 47 | * @param graph 48 | * the graph to be added 49 | */ 50 | void addGraph( Graph graph ); 51 | 52 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/retry/RetryServiceImpl.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.retry; 2 | 3 | import java.lang.invoke.MethodHandles; 4 | 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | import ee.telekom.workflow.core.error.ExecutionError; 12 | import ee.telekom.workflow.core.error.ExecutionErrorService; 13 | import ee.telekom.workflow.core.workflowinstance.WorkflowInstanceService; 14 | import ee.telekom.workflow.core.workitem.WorkItemService; 15 | 16 | @Service 17 | @Transactional 18 | public class RetryServiceImpl implements RetryService{ 19 | 20 | private static final Logger log = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() ); 21 | 22 | @Autowired 23 | private WorkflowInstanceService workflowInstanceService; 24 | @Autowired 25 | private WorkItemService workItemService; 26 | @Autowired 27 | private ExecutionErrorService executionErrorService; 28 | 29 | @Override 30 | public void retry( long woinRefNum ){ 31 | ExecutionError error = executionErrorService.findByWoinRefNum( woinRefNum ); 32 | log.info( "Retry execution of workflow instance " + error.getWoinRefNum() + (error.getWoitRefNum() == null ? "" : " " + error.getWoitRefNum()) ); 33 | workflowInstanceService.rewindAfterError( error.getWoinRefNum() ); 34 | if( error.getWoitRefNum() != null ){ 35 | workItemService.rewindAfterError( error.getWoitRefNum() ); 36 | } 37 | executionErrorService.delete( error.getRefNum() ); 38 | workflowInstanceService.unlock( error.getWoinRefNum() ); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/node/gateway/_03_SynchronizationTest.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import org.junit.Test; 4 | 5 | import ee.telekom.workflow.graph.AbstractGraphTest; 6 | import ee.telekom.workflow.graph.GraphFactory; 7 | 8 | public class _03_SynchronizationTest extends AbstractGraphTest{ 9 | 10 | @Test 11 | public void one(){ 12 | assertExecution( GraphFactory.INSTANCE.synchronzation_one(), "2" ); 13 | } 14 | 15 | @Test 16 | public void two(){ 17 | assertExecution( GraphFactory.INSTANCE.synchronzation_two(), "2,3" ); 18 | } 19 | 20 | @Test 21 | public void three(){ 22 | assertExecution( GraphFactory.INSTANCE.synchronzation_three(), "2,3,4" ); 23 | } 24 | 25 | @Test 26 | public void two_firstBranchEmpty(){ 27 | assertExecution( GraphFactory.INSTANCE.synchronzation_two_firstBranchEmpty(), "2" ); 28 | } 29 | 30 | @Test 31 | public void two_secondBranchEmpty(){ 32 | assertExecution( GraphFactory.INSTANCE.synchronzation_two_secondBranchEmpty(), "2" ); 33 | } 34 | 35 | @Test 36 | public void two_bothBranchesEmpty(){ 37 | assertExecution( GraphFactory.INSTANCE.synchronzation_two_bothBranchesEmpty(), null ); 38 | } 39 | 40 | @Test 41 | public void two_pre_post(){ 42 | assertExecution( GraphFactory.INSTANCE.synchronzation_two_pre_post(), "1,3,4,6" ); 43 | } 44 | 45 | @Test 46 | public void firstBranchEmpty_pre_post(){ 47 | assertExecution( GraphFactory.INSTANCE.synchronization_firstBranchEmpty_pre_post(), "1,3,6" ); 48 | } 49 | 50 | @Test 51 | public void secondBranchEmpty_pre_post(){ 52 | assertExecution( GraphFactory.INSTANCE.synchronization_secondBranchEmpty_pre_post(), "1,3,6" ); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/listener/HumanTaskEvent.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.listener; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * Provides details on the human task work item associated with the event, the workflow instance's id, 7 | * the workflow's name and version, the token id, role and user as well as the human task's arguments. 8 | * 9 | * The arguments must be used read-only! 10 | * 11 | * @author Christian Klock 12 | */ 13 | public class HumanTaskEvent{ 14 | 15 | private Long woinRefNum; 16 | private String workflowName; 17 | private Integer workflowVersion; 18 | private Integer tokenId; 19 | private String role; 20 | private String user; 21 | private Map arguments; 22 | 23 | public HumanTaskEvent( Long woinRefNum, String workflowName, Integer workflowVersion, Integer tokenId, String role, String user, 24 | Map arguments ){ 25 | this.woinRefNum = woinRefNum; 26 | this.workflowName = workflowName; 27 | this.workflowVersion = workflowVersion; 28 | this.tokenId = tokenId; 29 | this.role = role; 30 | this.user = user; 31 | this.arguments = arguments; 32 | } 33 | 34 | public Long getWoinRefNum(){ 35 | return woinRefNum; 36 | } 37 | 38 | public String getWorkflowName(){ 39 | return workflowName; 40 | } 41 | 42 | public Integer getWorkflowVersion(){ 43 | return workflowVersion; 44 | } 45 | 46 | public Integer getTokenId(){ 47 | return tokenId; 48 | } 49 | 50 | public String getRole(){ 51 | return role; 52 | } 53 | 54 | public String getUser(){ 55 | return user; 56 | } 57 | 58 | public Map getArguments(){ 59 | return arguments; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/gateway/CancellingDiscriminator.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import java.util.Collection; 4 | 5 | import ee.telekom.workflow.graph.GraphEngine; 6 | import ee.telekom.workflow.graph.GraphInstance; 7 | import ee.telekom.workflow.graph.Token; 8 | 9 | /** 10 | * Gateway, that implements the "cancelling discriminator" workflow pattern. That means, it continues the execution of the 11 | * subsequent branch once the first thread of execution arrives and cancels all other threads of execution that are originating 12 | * from the same fork. 13 | *

      14 | * The underlying token model restricts the usage of {@link AndJoin}s to be in balanced pairs with {@link AndFork} or {@link OrFork}s. 15 | */ 16 | public class CancellingDiscriminator extends AbstractGateway{ 17 | 18 | public CancellingDiscriminator( int id ){ 19 | super( id ); 20 | } 21 | 22 | public CancellingDiscriminator( int id, String name ){ 23 | super( id, name ); 24 | } 25 | 26 | @Override 27 | public void execute( GraphEngine engine, Token token ){ 28 | GraphInstance instance = token.getInstance(); 29 | Token parent = token.getParent(); 30 | 31 | token.markInactive(); 32 | // Making use of the fact that all sibling tokens originate from the same fork. 33 | Collection siblings = instance.getActiveChildTokens( parent ); 34 | for( Token sibling : siblings ){ 35 | engine.cancel( sibling ); 36 | } 37 | 38 | parent.setNode( this ); 39 | engine.complete( parent, null ); 40 | } 41 | 42 | @Override 43 | public void cancel( GraphEngine engine, Token token ){ 44 | // Tokens cannot "wait" at this kind of node. Hence, no "cancel" action is required. 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/recovery/RecoveryServiceImpl.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.recovery; 2 | 3 | import java.lang.invoke.MethodHandles; 4 | import java.util.List; 5 | 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.stereotype.Service; 10 | import org.springframework.transaction.annotation.Transactional; 11 | 12 | import ee.telekom.workflow.core.workflowinstance.WorkflowInstanceService; 13 | import ee.telekom.workflow.core.workitem.WorkItemService; 14 | 15 | @Service 16 | @Transactional 17 | public class RecoveryServiceImpl implements RecoveryService{ 18 | 19 | private static final Logger log = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() ); 20 | 21 | @Autowired 22 | private WorkflowInstanceService workflowInstanceService; 23 | @Autowired 24 | private WorkItemService workItemService; 25 | 26 | @Override 27 | public void recoverExecutionsAssignedToNodes( List deadNodes ){ 28 | for( String nodeName : deadNodes ){ 29 | log.info( "Running recovery for failed node {}", nodeName ); 30 | workItemService.recoverExecuting( nodeName ); 31 | workItemService.recoverCompleting( nodeName ); 32 | workflowInstanceService.recoverNew( nodeName ); 33 | workflowInstanceService.recoverExecuting( nodeName ); 34 | workflowInstanceService.recoverStarting( nodeName ); 35 | workflowInstanceService.recoverAbort( nodeName ); 36 | workflowInstanceService.recoverAborting( nodeName ); 37 | } 38 | } 39 | 40 | @Override 41 | public void recoverExecutionsNotAssignedToNodes( String clusterName ){ 42 | workflowInstanceService.recoverNotAssigned( clusterName ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /telekom-workflow-example/src/test/java/ee/telekom/workflow/example/definition/ExampleStep00Test.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.example.definition; 2 | 3 | import static org.mockito.ArgumentMatchers.anyString; 4 | import static org.mockito.Mockito.doReturn; 5 | import static org.mockito.Mockito.when; 6 | 7 | import java.util.Collections; 8 | import java.util.HashMap; 9 | 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | import org.mockito.Mock; 13 | import org.mockito.junit.MockitoJUnitRunner; 14 | 15 | import ee.telekom.workflow.test.AbstractWorkflowApiTest; 16 | 17 | /** 18 | * Example for how to write automated tests for workflow definitions. 19 | * 20 | * @author Raido Türk 21 | */ 22 | @RunWith(MockitoJUnitRunner.class) 23 | public class ExampleStep00Test extends AbstractWorkflowApiTest{ 24 | 25 | Example_00_StepSelection step0 = new Example_00_StepSelection(); 26 | 27 | @Mock 28 | ExampleStepSelector service; 29 | 30 | @Test 31 | public void should_go_to_step_1(){ 32 | doReturn( service ).when( beanResolver ).getBean( "exampleStepSelector" ); 33 | when( service.findNextStep( anyString(), anyString() ) ).thenReturn( Example_01_SendWarning.class.getCanonicalName() ); 34 | addGraphAndStartInstance( step0, createCustomerInput() ); 35 | 36 | assertActiveWorkItemsCount( 1 ); 37 | terminateTimer(); 38 | assertInstanceCompleted(); 39 | assertEnvironmentContainsValues( Collections.singletonMap( "nextStep", Example_01_SendWarning.class.getCanonicalName() ) ); 40 | verifyNewInstanceCreation( Example_01_SendWarning.class.getCanonicalName() ); 41 | } 42 | 43 | private HashMap createCustomerInput(){ 44 | HashMap map = new HashMap<>(); 45 | map.put( "customerId", "100001" ); 46 | return map; 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/util/CallUtil.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.util; 2 | 3 | import java.lang.reflect.InvocationTargetException; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Proxy; 6 | 7 | import org.springframework.aop.framework.Advised; 8 | 9 | import ee.telekom.workflow.graph.WorkflowException; 10 | 11 | 12 | public class CallUtil { 13 | 14 | public static Object call(Object target, String methodName, Object[] arguments) { 15 | Method method = MethodUtil.findMethod(target.getClass(), methodName, MethodUtil.getArgumentClasses(arguments)); 16 | String className = getTargetName(target); 17 | try { 18 | return method.invoke(target, arguments); 19 | } catch (IllegalAccessException e) { 20 | throw new WorkflowException("Invoking method '" + method.getName() + "' on class '" + className + "' failed", e); 21 | } catch (IllegalArgumentException e) { 22 | throw new WorkflowException("Invoking method '" + method.getName() + "' on class '" + className + "' failed", e); 23 | } catch (InvocationTargetException e) { 24 | throw new WorkflowException("Invoking method '" + method.getName() + "' on class '" + className + "' failed", e); 25 | } 26 | } 27 | 28 | private static String getTargetName(final Object target) { 29 | if (Proxy.isProxyClass(target.getClass())) { 30 | if (target instanceof Advised) { 31 | try { 32 | return ((Advised)target).getTargetSource().getTarget().getClass().getName(); 33 | } catch (Exception e) { 34 | // Nothing to do here. 35 | } 36 | } 37 | return target.getClass().getName() + " (unresolved proxy)"; 38 | } 39 | return target.getClass().getName(); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/gateway/AndJoin.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.gateway; 2 | 3 | import java.util.Collection; 4 | 5 | import ee.telekom.workflow.graph.GraphEngine; 6 | import ee.telekom.workflow.graph.GraphInstance; 7 | import ee.telekom.workflow.graph.Token; 8 | 9 | /** 10 | * Gateway, that implements the "structured synchronizing merge" workflow pattern. That means, it synchronises (re-joins) 11 | * the threads of execution that are originating from the paired {@link AndFork} or {@link OrFork}. Only when all threads 12 | * of execution arrived at the {@link AndJoin}, execution continues along the subsequent branch. 13 | *

      14 | * The underlying token model restricts the usage of {@link AndJoin}s to be in balanced pairs with {@link AndFork} or {@link OrFork}s. 15 | */ 16 | public class AndJoin extends AbstractGateway{ 17 | 18 | public AndJoin( int id ){ 19 | super( id ); 20 | } 21 | 22 | public AndJoin( int id, String name ){ 23 | super( id, name ); 24 | } 25 | 26 | @Override 27 | public void execute( GraphEngine engine, Token token ){ 28 | GraphInstance instance = token.getInstance(); 29 | Token parent = token.getParent(); 30 | 31 | token.markInactive(); 32 | // Making use of the fact that all sibling tokens originate from the same fork. 33 | Collection activeSiblings = instance.getActiveChildTokens( token.getParent() ); 34 | if( activeSiblings.isEmpty() ){ 35 | // This token is the last token of the group to arrive 36 | parent.setNode( this ); 37 | engine.complete( parent, null ); 38 | } 39 | } 40 | 41 | @Override 42 | public void cancel( GraphEngine engine, Token token ){ 43 | // Tokens cannot "wait" at this kind of node. Hence, no "cancel" action is required. 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/test/java/ee/telekom/workflow/graph/core/AbortInstanceTest.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.core; 2 | 3 | import org.junit.Test; 4 | 5 | import ee.telekom.workflow.graph.AbstractGraphTest; 6 | import ee.telekom.workflow.graph.Graph; 7 | import ee.telekom.workflow.graph.GraphEngineFacade; 8 | import ee.telekom.workflow.graph.GraphFactory; 9 | import ee.telekom.workflow.graph.GraphInstance; 10 | 11 | public class AbortInstanceTest extends AbstractGraphTest{ 12 | 13 | @Test 14 | public void abort_with_signals(){ 15 | Graph graph = GraphFactory.INSTANCE.escalation_three(); 16 | assertAbort( graph, 4, 3 ); 17 | } 18 | 19 | @Test 20 | public void abort_with_timer(){ 21 | Graph graph = GraphFactory.INSTANCE.timer_one_pre_post(); 22 | assertAbort( graph, 1, 1 ); 23 | } 24 | 25 | @Test 26 | public void abort_with_timer_parallel(){ 27 | Graph graph = GraphFactory.INSTANCE.timer_parallel_pre_post(); 28 | assertAbort( graph, 3, 2 ); 29 | } 30 | 31 | @Test 32 | public void abort_with_task(){ 33 | Graph graph = GraphFactory.INSTANCE.beanasynccall_one_pre_post(); 34 | assertAbort( graph, 1, 1 ); 35 | } 36 | 37 | @Test 38 | public void abort_with_human_task(){ 39 | Graph graph = GraphFactory.INSTANCE.human_task_one_pre_post(); 40 | assertAbort( graph, 1, 1 ); 41 | } 42 | 43 | private void assertAbort( Graph graph, int activeTokens, int activeWorkItems ){ 44 | GraphEngineFacade engine = new GraphEngineImpl(); 45 | GraphInstance instance = engine.start( graph, null ); 46 | assertActiveTokens( instance, activeTokens ); 47 | assertActiveWorkItems( instance, activeWorkItems ); 48 | 49 | engine.abort( instance ); 50 | assertActiveWorkItems( instance, 0 ); 51 | assertActiveTokens( instance, 0 ); 52 | 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/java/ee/telekom/workflow/web/util/JdbcDriverDeregisterListener.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.web.util; 2 | 3 | import java.lang.invoke.MethodHandles; 4 | import java.sql.Driver; 5 | import java.sql.DriverManager; 6 | import java.sql.SQLException; 7 | import java.util.Enumeration; 8 | 9 | import jakarta.servlet.ServletContextEvent; 10 | import jakarta.servlet.ServletContextListener; 11 | 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | 15 | /** 16 | * Servlet context destory hook: de-register JDBC drivers to properly release resources. 17 | * 18 | * @author Christian Klock 19 | * @author Erko Hansar 20 | * @see http://stackoverflow.com/a/23912257/2767952 21 | */ 22 | public class JdbcDriverDeregisterListener implements ServletContextListener{ 23 | 24 | private static final Logger log = LoggerFactory.getLogger( MethodHandles.lookup().lookupClass() ); 25 | 26 | @Override 27 | public void contextInitialized( ServletContextEvent sce ){ 28 | // nothing to do here 29 | } 30 | 31 | @Override 32 | public void contextDestroyed( ServletContextEvent sce ){ 33 | ClassLoader thisClassLoader = this.getClass().getClassLoader(); 34 | Enumeration drivers = DriverManager.getDrivers(); 35 | while( drivers.hasMoreElements() ){ 36 | Driver driver = drivers.nextElement(); 37 | // only process drivers loaded by this web application 38 | if( driver.getClass().getClassLoader() == thisClassLoader ){ 39 | try{ 40 | log.info( "Deregistering JDBC driver {}", driver ); 41 | DriverManager.deregisterDriver( driver ); 42 | } 43 | catch( SQLException ex ){ 44 | log.error( "Error deregistering JDBC driver {}", driver, ex ); 45 | } 46 | } 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/core/error/ExecutionErrorDao.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.core.error; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | 6 | import org.springframework.stereotype.Repository; 7 | 8 | import ee.telekom.workflow.util.AbstractWorkflowEngineDao; 9 | import ee.telekom.workflow.util.AdvancedParameterSource; 10 | 11 | @Repository 12 | public class ExecutionErrorDao extends AbstractWorkflowEngineDao{ 13 | 14 | public void create( ExecutionError error ){ 15 | long refNum = getNextSequenceValue( getSchema() + "exer_ref_num_s" ); 16 | error.setRefNum( refNum ); 17 | String sql = "" 18 | + "INSERT INTO " + getSchema() + "execution_errors " 19 | + " (ref_num, woin_ref_num, woit_ref_num, error_text, error_details, date_created, created_by) " 20 | + " VALUES " 21 | + " (:refNum, :woinRefNum, :woitRefNum, :errorText, :errorDetails, :dateCreated, :createdBy)"; 22 | AdvancedParameterSource source = new AdvancedParameterSource() 23 | .addBean( error ) 24 | .addValue( "dateCreated", new Date() ) 25 | .addValue( "createdBy", getCreatedOrLastUpdatedBy() ); 26 | getNamedParameterJdbcTemplate().update( sql, source ); 27 | } 28 | 29 | public ExecutionError findByWoinRefNum( long woinRefNum ){ 30 | String sql = "SELECT * FROM " + getSchema() + "execution_errors WHERE woin_ref_num = ?"; 31 | List result = getJdbcTemplate().query( sql, ExecutionErrorRowMapper.INSTANCE, woinRefNum ); 32 | return result.isEmpty() ? null : result.getFirst(); 33 | } 34 | 35 | public void delete( long refNum ){ 36 | String sql = "DELETE FROM " + getSchema() + "execution_errors WHERE ref_num = ?"; 37 | Object[] args = {refNum}; 38 | getJdbcTemplate().update( sql, args ); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/Token.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph; 2 | 3 | /** 4 | * A {@link Token} points to a {@link Node} in a {@link Graph}. The set of active tokens in a {@link GraphInstance} mark the graph instance's flow state. 5 | */ 6 | public interface Token { 7 | 8 | /** 9 | * Returns the token's id. The id is unique among the token's in the 10 | * containing graph instance. 11 | * 12 | * @return the token's id 13 | */ 14 | int getId(); 15 | 16 | /** 17 | * Returns the {@link Node} that this token is pointing to. 18 | * 19 | * @return the node that this token is pointing to 20 | */ 21 | Node getNode(); 22 | 23 | /** 24 | * Sets the {@link Node} that the token is pointing to. 25 | * 26 | * @param node 27 | * the new node to point to 28 | */ 29 | void setNode(Node node); 30 | 31 | /** 32 | * Returns the {@link GraphInstance} that this token belongs to. 33 | * 34 | * @return the graph instance that this token belongs to 35 | */ 36 | GraphInstance getInstance(); 37 | 38 | /** 39 | * Returns the parent token which was involved in creating this token. If 40 | * this node is a {@link GraphInstance}'s main token (the token that begins 41 | * executing at the start node), null will be returned. 42 | * 43 | * @return the token's parent token or null for a main token 44 | */ 45 | Token getParent(); 46 | 47 | /** 48 | * Marks this token as inactive, in the sense that it no longer represents 49 | * an active part of the workflow instance. Once a token is marked inactive, 50 | * it is generally only of historical interest. 51 | * 52 | * A token may be marked inactive because its execution has completed or it 53 | * has been cancelled. 54 | */ 55 | void markInactive(); 56 | 57 | /** 58 | * Returns whether the token is active. 59 | * 60 | * @return true, if the token is active 61 | */ 62 | boolean isActive(); 63 | 64 | } -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/graph/node/event/ThrowEscalation.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.graph.node.event; 2 | 3 | import ee.telekom.workflow.graph.Environment; 4 | import ee.telekom.workflow.graph.GraphEngine; 5 | import ee.telekom.workflow.graph.Token; 6 | import ee.telekom.workflow.graph.node.AbstractNode; 7 | 8 | /** 9 | * Throw event, cancelling all active token siblings. This kind of event can be used to 10 | * model escalation boundaries known from BPMN where different actions need to be taken 11 | * depending on whether the main activity succeeded or an escalation event cancelled the 12 | * main activity.
      13 | * The following figure depicts such a control flow 14 | *

      15 |  *          +--[main]-------------[escalation]--[success-activity]--------+
      16 |  * [1]--[AND]--[escalate-event1]--[escalation]--[escalation1-resolution]--[AND]--[13]
      17 |  *          +--[escalate-event2]--[escalation]--[escalation2-resolution]--+
      18 |  * 
      19 | */ 20 | public class ThrowEscalation extends AbstractNode{ 21 | 22 | public ThrowEscalation( int id ){ 23 | super( id ); 24 | } 25 | 26 | public ThrowEscalation( int id, String name ){ 27 | super( id, name ); 28 | } 29 | 30 | @Override 31 | public void execute( GraphEngine engine, Token token ){ 32 | for( Token other : token.getInstance().getActiveChildTokens( token.getParent() ) ){ 33 | if( other != token ){ 34 | engine.cancel( other ); 35 | } 36 | } 37 | engine.complete( token, null ); 38 | } 39 | 40 | @Override 41 | public void cancel( GraphEngine engine, Token token ){ 42 | // Tokens cannot "wait" at this kind of node since the execution 43 | // is synchronous. Hence, no "cancel" action is required. 44 | } 45 | 46 | @Override 47 | public void store( Environment environment, Object result ){ 48 | // This type of node does not produce or expect a result 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /telekom-workflow-example/src/main/java/ee/telekom/workflow/example/definition/Example_00_StepSelection.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.example.definition; 2 | 3 | import org.springframework.stereotype.Component; 4 | 5 | import ee.telekom.workflow.api.WorkflowDefinition; 6 | import ee.telekom.workflow.api.WorkflowFactory; 7 | 8 | /** 9 | * An example workflow definition via DSL. 10 | * 11 | * This workflow is divided into sub-workflows called "steps". This is the initial step that waits a given time before starting 12 | * the execution and then find the next appropriate step based on the customer status. 13 | * 14 | * @author Erko Hansar 15 | */ 16 | @Component 17 | public class Example_00_StepSelection implements WorkflowDefinition{ 18 | 19 | @Override 20 | public String getName(){ 21 | return this.getClass().getCanonicalName(); 22 | } 23 | 24 | @Override 25 | public int getVersion(){ 26 | return 1; 27 | } 28 | 29 | @Override 30 | public void configureWorkflowDefinition( WorkflowFactory factory ){ 31 | /* @formatter:off */ 32 | factory 33 | .start() 34 | 35 | // define customerId as a required input variable 36 | .validateInputVariable( 0, "customerId", String.class ) 37 | // define waitTime as an optional input variable with a default value 38 | .validateInputVariable( 1, "waitTime", Long.class, false, 1000L * 30 ) 39 | // wait for the waitTime duration 40 | .waitTimer( 2, "${waitTime}" ) 41 | 42 | // find out the next step 43 | .variable( "nextStep" ).call( 3, "exampleStepSelector", "findNextStep", "${customerId}", "00" ) 44 | // and start it, passing along the customerId attribute 45 | .createInstance( 4, "${nextStep}", null, "${customerId}", null ).withAttribute( "customerId", "${customerId}" ).done() 46 | 47 | .end(); 48 | /* @formatter:on */ 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /telekom-workflow-web/src/main/resources/META-INF/resources/WEB-INF/jsp-twe/console/workflow/item.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true" %> 2 | <%@ include file="../../header.jspf" %> 3 | 4 | 5 |
      6 |
      7 | 8 |
      9 | 10 |
      11 |
      12 | 13 |
      14 |
      15 |

      16 | 17 | 18 | 19 | 20 | 21 | 26 | 30 | 31 | 32 |
      22 | 25 | 27 | 28 | 29 |
      33 |
      34 |

      35 | 36 | 37 | 38 | 39 | 40 |
      41 |
      42 |
      43 |
      44 |
      45 | 46 | <%@ include file="../../footer.jspf" %> -------------------------------------------------------------------------------- /telekom-workflow-api/src/main/java/ee/telekom/workflow/facade/model/ExecutionErrorState.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.facade.model; 2 | 3 | /** 4 | * Model object that provides details on an execution error. 5 | * 6 | * @author Christian Klock 7 | */ 8 | public class ExecutionErrorState{ 9 | 10 | private Long refNum; 11 | private Long woinRefNum; 12 | private Long woitRefNum; 13 | private String errorText; 14 | private String errorDetails; 15 | 16 | /** 17 | * @return the execution error's internal id. 18 | */ 19 | public Long getRefNum(){ 20 | return refNum; 21 | } 22 | 23 | public void setRefNum( Long refNum ){ 24 | this.refNum = refNum; 25 | } 26 | 27 | /** 28 | * @return the concerned workflow instance's internal id, never null. 29 | */ 30 | public Long getWoinRefNum(){ 31 | return woinRefNum; 32 | } 33 | 34 | public void setWoinRefNum( Long woinRefNum ){ 35 | this.woinRefNum = woinRefNum; 36 | } 37 | 38 | /** 39 | * @return the concerned work item's id. Null, if error occurred while performing an 40 | * action on the instance (e.g. start/abort instance) rather than on a work item (e.g. execute task, complete work item). 41 | */ 42 | public Long getWoitRefNum(){ 43 | return woitRefNum; 44 | } 45 | 46 | public void setWoitRefNum( Long woitRefNum ){ 47 | this.woitRefNum = woitRefNum; 48 | } 49 | 50 | /** 51 | * @return the thrown exception's error message. 52 | */ 53 | public String getErrorText(){ 54 | return errorText; 55 | } 56 | 57 | public void setErrorText( String errorText ){ 58 | this.errorText = errorText; 59 | } 60 | 61 | /** 62 | * @return the thrown exception's stack trace. 63 | */ 64 | public String getErrorDetails(){ 65 | return errorDetails; 66 | } 67 | 68 | public void setErrorDetails( String errorDetails ){ 69 | this.errorDetails = errorDetails; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /telekom-workflow-engine/src/main/java/ee/telekom/workflow/jmx/EngineMonitor.java: -------------------------------------------------------------------------------- 1 | package ee.telekom.workflow.jmx; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.jmx.export.annotation.ManagedAttribute; 5 | import org.springframework.jmx.export.annotation.ManagedResource; 6 | import org.springframework.stereotype.Component; 7 | 8 | import ee.telekom.workflow.executor.consumer.WorkConsumerService; 9 | import ee.telekom.workflow.executor.plugin.WorkflowEnginePlugin; 10 | import ee.telekom.workflow.executor.producer.WorkProducerJob; 11 | import ee.telekom.workflow.executor.queue.WorkQueue; 12 | 13 | @Component(EngineMonitor.BEAN) 14 | @ManagedResource 15 | public class EngineMonitor{ 16 | 17 | // The bean's name is used to reference the bean in an XML application context file. 18 | // Therefore, we explicitly set the bean name to a constant. 19 | public static final String BEAN = "engineMonitor"; 20 | 21 | @Autowired 22 | private WorkflowEnginePlugin plugin; 23 | @Autowired 24 | private WorkQueue queue; 25 | @Autowired 26 | private WorkProducerJob producerJob; 27 | @Autowired 28 | private WorkConsumerService consumerService; 29 | 30 | @ManagedAttribute(description = "Is plugin started") 31 | public boolean isPluginStarted(){ 32 | return plugin.isStarted(); 33 | } 34 | 35 | @ManagedAttribute(description = "Is queue started") 36 | public boolean isQueueStarted(){ 37 | return queue.isStarted(); 38 | } 39 | 40 | @ManagedAttribute(description = "Is producer started") 41 | public boolean isProducerStarted(){ 42 | return producerJob.isStarted(); 43 | } 44 | 45 | @ManagedAttribute(description = "Is producer suspended") 46 | public boolean isProducerSuspended(){ 47 | return producerJob.isSuspended(); 48 | } 49 | 50 | @ManagedAttribute(description = "Consumed work units") 51 | public long getConsumedWorkUnits(){ 52 | return consumerService.getConsumedWorkUnits(); 53 | } 54 | 55 | } 56 | --------------------------------------------------------------------------------