adding the sandbox project for spring-integration-activiti
This commit is contained in:
1
pom.xml
1
pom.xml
@@ -29,6 +29,7 @@
|
||||
<module>spring-integration-ftp</module>
|
||||
<module>spring-integration-sftp</module>
|
||||
<module>spring-integration-twitter</module>
|
||||
<module>spring-integration-activiti</module>
|
||||
</modules>
|
||||
<scm>
|
||||
<connection>scm:svn:https://src.springframework.org/svn/spring-integration/trunk</connection>
|
||||
|
||||
102
spring-integration-activiti/pom.xml
Normal file
102
spring-integration-activiti/pom.xml
Normal file
@@ -0,0 +1,102 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-parent</artifactId>
|
||||
<version>2.0.0.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-activiti</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Integration Activiti Support</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>commons-dbcp</groupId>
|
||||
<artifactId>commons-dbcp</artifactId>
|
||||
<version>1.2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib-nodep</artifactId>
|
||||
<version>2.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-core</artifactId>
|
||||
<version>3.0.3.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-orm</artifactId>
|
||||
<version>3.0.3.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
<version>3.0.3.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<version>3.0.3.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-event</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-jms</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<version>3.0.3.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context-support</artifactId>
|
||||
<version>3.0.3.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-aop</artifactId>
|
||||
<version>3.0.3.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<version>1.2.132</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.activiti</groupId>
|
||||
<artifactId>activiti-engine</artifactId>
|
||||
<version>5.0.beta1</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<!-- <plugins>
|
||||
<plugin>
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
</plugins> -->
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,35 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti;
|
||||
|
||||
/**
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class ActivitiConstants {
|
||||
|
||||
/**
|
||||
* In order for the gateway to correctly signal execution to Activiti, it needs to the executionId so that it can look up the {@link org.activiti.engine.runtime.Execution} instance.
|
||||
* the <code>executionId</code> is expected to be under this header.
|
||||
*/
|
||||
public static final String WELL_KNOWN_EXECUTION_ID_HEADER_KEY = "activiti_spring_integration_executionId";
|
||||
|
||||
/**
|
||||
* Assuming #updateProcessVariablesFromReplyMessageHeaders is true, then any {@link org.springframework.integration.MessageHeaders} header key that starts with String will be propagated as an Activiti process variable.
|
||||
*/
|
||||
public static final String WELL_KNOWN_SPRING_INTEGRATION_HEADER_PREFIX = "activiti_spring_integration_";
|
||||
|
||||
/**
|
||||
* This is the key under which we will look up the custom <code>processDefinitionName</code> up. This value will be used to spawn
|
||||
*/
|
||||
public static final String WELL_KNOWN_PROCESS_DEFINITION_NAME_HEADER_KEY = "activiti_spring_integration_processDefinitionName";
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.activiti;
|
||||
|
||||
import org.springframework.integration.MessageHeaders;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentSkipListSet;
|
||||
|
||||
|
||||
/**
|
||||
* Provides utility logic to take headers from a {@link org.springframework.integration.MessageHeaders} instance and propagate them as
|
||||
* values that can be used as process variables for a {@link org.activiti.engine.runtime.ProcessInstance}.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class ProcessSupport {
|
||||
private final int headerPrefixLength = ActivitiConstants.WELL_KNOWN_SPRING_INTEGRATION_HEADER_PREFIX.length();
|
||||
private Collection<String> blackList;
|
||||
|
||||
public ProcessSupport() {
|
||||
this.blackList = new ConcurrentSkipListSet<String>(Arrays.asList(ActivitiConstants.WELL_KNOWN_EXECUTION_ID_HEADER_KEY, ActivitiConstants.WELL_KNOWN_PROCESS_DEFINITION_NAME_HEADER_KEY));
|
||||
}
|
||||
|
||||
public Map<String, Object> processVariablesFromMessageHeaders(MessageHeaders msg) {
|
||||
return this.processVariablesFromMessageHeaders(new HashSet<String>(), msg);
|
||||
}
|
||||
|
||||
public Map<String, Object> processVariablesFromMessageHeaders(Set<String> whiteListOfMustCopyMessageHeaderKeyNames, MessageHeaders msgHeaders) {
|
||||
Map<String, Object> procVars = new HashMap<String, Object>();
|
||||
|
||||
Set<String> headers = msgHeaders.keySet();
|
||||
Set<String> wl = (whiteListOfMustCopyMessageHeaderKeyNames == null) ? new HashSet<String>() : whiteListOfMustCopyMessageHeaderKeyNames;
|
||||
|
||||
for (String messageHeaderKey : headers) {
|
||||
if ((!blackList.contains(messageHeaderKey) && messageHeaderKey.startsWith(ActivitiConstants.WELL_KNOWN_SPRING_INTEGRATION_HEADER_PREFIX)) || wl.contains(messageHeaderKey)) {
|
||||
String pvName = messageHeaderKey.startsWith(ActivitiConstants.WELL_KNOWN_SPRING_INTEGRATION_HEADER_PREFIX) ? messageHeaderKey.substring(headerPrefixLength) : messageHeaderKey;
|
||||
procVars.put(pvName, msgHeaders.get(messageHeaderKey));
|
||||
}
|
||||
}
|
||||
|
||||
return procVars;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti.adapter;
|
||||
|
||||
import org.activiti.engine.ProcessEngine;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.activiti.ActivitiConstants;
|
||||
import org.springframework.integration.activiti.ProcessSupport;
|
||||
import org.springframework.integration.context.IntegrationObjectSupport;
|
||||
import org.springframework.integration.core.MessageHandler;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* Supports spawning a {@link org.activiti.engine.runtime.ProcessInstance} as a result of a trigger {@link org.springframework.integration.Message}.
|
||||
* <p/>
|
||||
* The component also supports propagating headers as processVariables.
|
||||
* <p/>
|
||||
* This support is simialar to the classic EIP book's "Process Manager" pattern.
|
||||
* <p/>
|
||||
* Thanks to Mark Fisherfor the idea.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class ActivitiOutboundChannelAdapter extends IntegrationObjectSupport implements MessageHandler {
|
||||
/**
|
||||
* A reference to the {@link ProcessEngine} (see {@link org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean}
|
||||
*/
|
||||
private ProcessEngine processEngine;
|
||||
|
||||
/**
|
||||
* Do you want all flows that come into this component to launch the same business process? Hard code the process name here.
|
||||
* If this is null, the component will expect a well known header value and use that to spawn the process definition name.
|
||||
*/
|
||||
private String processDefinitionName;
|
||||
|
||||
/**
|
||||
* Provides convenience methods
|
||||
*/
|
||||
private ProcessSupport processSupport = new ProcessSupport();
|
||||
|
||||
@Override
|
||||
protected void onInit() throws Exception {
|
||||
Assert.notNull(this.processEngine, "'processEngine' is required!");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setProcessEngine(ProcessEngine processEngine) {
|
||||
this.processEngine = processEngine;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setProcessDefinitionName(String processDefinitionName) {
|
||||
this.processDefinitionName = processDefinitionName;
|
||||
}
|
||||
|
||||
public void handleMessage(Message<?> message) {
|
||||
Map<String, Object> procVars = processSupport.processVariablesFromMessageHeaders(message.getHeaders());
|
||||
|
||||
String procName = (String) message.getHeaders().get(ActivitiConstants.WELL_KNOWN_PROCESS_DEFINITION_NAME_HEADER_KEY);
|
||||
|
||||
if ((procName == null) || procName.trim().equals("")) {
|
||||
procName = this.processDefinitionName;
|
||||
}
|
||||
|
||||
Assert.isTrue(procName != null,
|
||||
"you must specify a processDefinitionName, either through " +
|
||||
"an inbound header mapped to the key " + ActivitiConstants.WELL_KNOWN_PROCESS_DEFINITION_NAME_HEADER_KEY +
|
||||
", or on the 'process-definition-name' property of this adapter"
|
||||
);
|
||||
|
||||
processEngine.getRuntimeService().startProcessInstanceByKey(this.processDefinitionName, procVars);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2010 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti.config;
|
||||
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.activiti.adapter.ActivitiOutboundChannelAdapter;
|
||||
import org.springframework.integration.activiti.gateway.ActivityBehaviorMessagingGatewayFactoryBean;
|
||||
import org.springframework.integration.config.xml.AbstractOutboundChannelAdapterParser;
|
||||
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
/**
|
||||
* Provides namespace support for defining a Gateway that communicates <em>from</em> Acitviti <em>to</em> Spring Integration.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class ActivitiNamespaceHandler extends NamespaceHandlerSupport {
|
||||
|
||||
public void init() {
|
||||
this.registerBeanDefinitionParser("inbound-gateway", new ActivitiInboundGatewayParser());
|
||||
this.registerBeanDefinitionParser("outbound-channel-adapter", new ActivitiOutboundChannelAdapterParser());
|
||||
}
|
||||
|
||||
private static class ActivitiOutboundChannelAdapterParser extends AbstractOutboundChannelAdapterParser {
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseConsumer(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ActivitiOutboundChannelAdapter.class.getName());
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "process-engine");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "process-definition-name");
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ActivitiInboundGatewayParser extends AbstractSingleBeanDefinitionParser {
|
||||
@Override
|
||||
protected String getBeanClassName(Element element) {
|
||||
return ActivityBehaviorMessagingGatewayFactoryBean.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldGenerateIdAsFallback() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "request-channel");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "reply-channel");
|
||||
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "process-engine");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "update-process-variables-from-reply-message-headers");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "async");
|
||||
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "forward-process-variables-as-message-headers");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package org.springframework.integration.activiti.gateway;
|
||||
|
||||
import org.activiti.engine.ProcessEngine;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
|
||||
import org.springframework.integration.MessageChannel;
|
||||
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
|
||||
public class ActivityBehaviorMessagingGatewayFactoryBean implements FactoryBean, BeanFactoryAware, BeanNameAware {
|
||||
private volatile boolean updateProcessVariablesFromReplyMessageHeaders = false;
|
||||
private volatile boolean forwardProcessVariablesAsMessageHeaders = false;
|
||||
private volatile PlatformTransactionManager platformTransactionManager;
|
||||
private volatile MessageChannel requestChannel;
|
||||
private volatile MessageChannel replyChannel;
|
||||
private volatile ProcessEngine processEngine;
|
||||
private volatile boolean async;
|
||||
private BeanFactory beanFactory;
|
||||
private String beanName;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setAsync(boolean async) {
|
||||
this.async = async;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setProcessEngine(ProcessEngine processEngine) {
|
||||
this.processEngine = processEngine;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setUpdateProcessVariablesFromReplyMessageHeaders(boolean updateProcessVariablesFromReplyMessageHeaders) {
|
||||
this.updateProcessVariablesFromReplyMessageHeaders = updateProcessVariablesFromReplyMessageHeaders;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setForwardProcessVariablesAsMessageHeaders(boolean forwardProcessVariablesAsMessageHeaders) {
|
||||
this.forwardProcessVariablesAsMessageHeaders = forwardProcessVariablesAsMessageHeaders;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
|
||||
this.platformTransactionManager = platformTransactionManager;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setRequestChannel(MessageChannel requestChannel) {
|
||||
this.requestChannel = requestChannel;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setBeanFactory(BeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setReplyChannel(MessageChannel replyChannel) {
|
||||
this.replyChannel = replyChannel;
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
if (this.async) {
|
||||
AsyncActivityBehaviorMessagingGateway asyncActivityBehaviorMessagingGateway = new AsyncActivityBehaviorMessagingGateway();
|
||||
asyncActivityBehaviorMessagingGateway.setForwardProcessVariablesAsMessageHeaders(this.forwardProcessVariablesAsMessageHeaders);
|
||||
asyncActivityBehaviorMessagingGateway.setUpdateProcessVariablesFromReplyMessageHeaders(this.updateProcessVariablesFromReplyMessageHeaders);
|
||||
asyncActivityBehaviorMessagingGateway.setPlatformTransactionManager(this.platformTransactionManager);
|
||||
asyncActivityBehaviorMessagingGateway.setReplyChannel(this.replyChannel);
|
||||
asyncActivityBehaviorMessagingGateway.setProcessEngine(this.processEngine);
|
||||
asyncActivityBehaviorMessagingGateway.setRequestChannel(this.requestChannel);
|
||||
asyncActivityBehaviorMessagingGateway.setBeanFactory(this.beanFactory);
|
||||
asyncActivityBehaviorMessagingGateway.setBeanName(this.beanName);
|
||||
asyncActivityBehaviorMessagingGateway.afterPropertiesSet();
|
||||
|
||||
return asyncActivityBehaviorMessagingGateway;
|
||||
} else {
|
||||
SyncActivityBehaviorMessagingGateway syncActivityBehaviorMessagingGateway = new SyncActivityBehaviorMessagingGateway();
|
||||
syncActivityBehaviorMessagingGateway.setForwardProcessVariablesAsMessageHeaders(this.forwardProcessVariablesAsMessageHeaders);
|
||||
syncActivityBehaviorMessagingGateway.setUpdateProcessVariablesFromReplyMessageHeaders(this.updateProcessVariablesFromReplyMessageHeaders);
|
||||
syncActivityBehaviorMessagingGateway.setPlatformTransactionManager(this.platformTransactionManager);
|
||||
syncActivityBehaviorMessagingGateway.setReplyChannel(this.replyChannel);
|
||||
syncActivityBehaviorMessagingGateway.setProcessEngine(this.processEngine);
|
||||
syncActivityBehaviorMessagingGateway.setRequestChannel(this.requestChannel);
|
||||
syncActivityBehaviorMessagingGateway.setBeanFactory(this.beanFactory);
|
||||
syncActivityBehaviorMessagingGateway.setBeanName(this.beanName);
|
||||
syncActivityBehaviorMessagingGateway.afterPropertiesSet();
|
||||
|
||||
return syncActivityBehaviorMessagingGateway;
|
||||
}
|
||||
}
|
||||
|
||||
public Class<?> getObjectType() {
|
||||
return this.async ? AsyncActivityBehaviorMessagingGateway.class : SyncActivityBehaviorMessagingGateway.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setBeanName(String name) {
|
||||
this.beanName = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,263 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti.gateway;
|
||||
|
||||
|
||||
import org.activiti.engine.ProcessEngine;
|
||||
import org.activiti.engine.RuntimeService;
|
||||
import org.activiti.engine.impl.bpmn.ReceiveTaskActivity;
|
||||
import org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean;
|
||||
import org.activiti.pvm.activity.ActivityBehavior;
|
||||
import org.activiti.pvm.activity.ActivityExecution;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.*;
|
||||
import org.springframework.integration.activiti.ActivitiConstants;
|
||||
import org.springframework.integration.activiti.ProcessSupport;
|
||||
import org.springframework.integration.config.ConsumerEndpointFactoryBean;
|
||||
import org.springframework.integration.core.*;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.scheduling.PollerMetadata;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.scheduling.support.PeriodicTrigger;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.activiti.engine.runtime.Execution ;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* This class is plugged into an Activiti workflow. <serviceTask /> let's us plugin a custom {@link ActivityBehavior}.
|
||||
* We need to build an {@link ActivityBehavior} that can send and receive the message,
|
||||
* propagating the {@code executionId} and potentially process variables/ header variables.
|
||||
* <p/>
|
||||
* Simply <code>svn co http://svn.codehaus.org/activiti/activiti/branches/alpha4-spring-integration-adapter</code> that repository and then <code>mvn clean install </code> it.
|
||||
* <p/>
|
||||
* The class forwards ("pushes") control from a BPM process (in-thread) to a Spring Integration channel where, of course, Spring Integration acts as a client and
|
||||
* can push the execution forward anyway it wants to.
|
||||
* <p/>
|
||||
* Possible use cases include forwarding the job through an outbound JMS adapter or gateway, forwarding the job through an XMPP adapter, or forwarding the job through
|
||||
* to an outbound email adapter.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* The only requirement for the reply is that the {@link org.springframework.integration.Message} arrive on the #replyChannel and that it contain a header of
|
||||
* {@link org.springframework.integration.activiti.ActivitiConstants#WELL_KNOWN_EXECUTION_ID_HEADER_KEY} (which the outbound {@link org.springframework.integration.Message} will have)
|
||||
* so that the Activiti runtime can signal that execution has completed successfully.
|
||||
* <p/>
|
||||
* Thanks to Dave Syer and Tom Baeyens for the help brainstorming.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @see ReceiveTaskActivity the {@link ActivityBehavior} impl that ships w/ Activiti that has the machinery to wake up when signaled
|
||||
* @see ProcessEngine the process engine instance is required to be able to use this namespace
|
||||
* @see ProcessEngineFactoryBean - use this class to create the aforementioned ProcessEngine instance!
|
||||
*/
|
||||
public class AsyncActivityBehaviorMessagingGateway extends ReceiveTaskActivity implements BeanFactoryAware, BeanNameAware, ActivityBehavior, InitializingBean {
|
||||
/**
|
||||
* Used to handle sending in a standard way
|
||||
*/
|
||||
private MessagingTemplate messagingTemplate = new MessagingTemplate();
|
||||
|
||||
/**
|
||||
* This is the channel on which we expect requests - {@link Execution}s from Activiti - to arrive
|
||||
*/
|
||||
private volatile MessageChannel requestChannel;
|
||||
|
||||
/**
|
||||
* This is the channel on which we expect to send replies - ie, the result of our work in
|
||||
* Spring Integration - back to Activiti, which should be waiting for the results
|
||||
*/
|
||||
private volatile MessageChannel replyChannel;
|
||||
|
||||
/**
|
||||
* Injected from Spring or some other mechanism. Recommended approach is through a {@link ProcessEngineFactoryBean}
|
||||
*/
|
||||
private volatile ProcessEngine processEngine;
|
||||
|
||||
/**
|
||||
* Should we update the process variables based on the reply {@link org.springframework.integration.Message}'s {@link org.springframework.integration.MessageHeaders}?
|
||||
*/
|
||||
private volatile boolean updateProcessVariablesFromReplyMessageHeaders = false;
|
||||
|
||||
/**
|
||||
* Should we pass the workflow process variables as message headers when we send a message into the Spring Integration framework?
|
||||
*/
|
||||
private volatile boolean forwardProcessVariablesAsMessageHeaders = false;
|
||||
|
||||
/**
|
||||
* Forwarded to the {@link org.springframework.integration.core.MessagingTemplate} instance.
|
||||
*/
|
||||
private volatile PlatformTransactionManager platformTransactionManager;
|
||||
|
||||
/**
|
||||
* A reference to the {@link org.springframework.beans.factory.BeanFactory} that's hosting this component. Spring will inject this reference automatically assuming
|
||||
* this object is hosted in a Spring context.
|
||||
*/
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* The process engine instance that controls the Activiti PVM. Recommended creation is through {@link ProcessEngineFactoryBean}
|
||||
*/
|
||||
private RuntimeService processService;
|
||||
|
||||
/**
|
||||
* Provides common logic for things like sifting through inbound message headers and arriving at process variable candidates
|
||||
*/
|
||||
private ProcessSupport processSupport = new ProcessSupport();
|
||||
private String beanName;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
|
||||
this.platformTransactionManager = platformTransactionManager;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setRequestChannel(MessageChannel requestChannel) {
|
||||
this.requestChannel = requestChannel;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setReplyChannel(MessageChannel replyChannel) {
|
||||
this.replyChannel = replyChannel;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setProcessEngine(ProcessEngine processEngine) {
|
||||
this.processEngine = processEngine;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setForwardProcessVariablesAsMessageHeaders(boolean forwardProcessVariablesAsMessageHeaders) {
|
||||
this.forwardProcessVariablesAsMessageHeaders = forwardProcessVariablesAsMessageHeaders;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setUpdateProcessVariablesFromReplyMessageHeaders(boolean updateProcessVariablesFromReplyMessageHeaders) {
|
||||
this.updateProcessVariablesFromReplyMessageHeaders = updateProcessVariablesFromReplyMessageHeaders;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void signal(ActivityExecution execution, String signalName, Object data) throws Exception {
|
||||
|
||||
if (data instanceof MessageHeaders) {
|
||||
MessageHeaders messageHeaders = (MessageHeaders) data;
|
||||
|
||||
if (this.updateProcessVariablesFromReplyMessageHeaders) {
|
||||
Map<String, Object> vars = execution .getVariables();
|
||||
Set<String> existingVars = vars.keySet();
|
||||
|
||||
Map<String, Object> procVars = this.processSupport.processVariablesFromMessageHeaders(existingVars, messageHeaders);
|
||||
|
||||
for (String key : procVars.keySet())
|
||||
execution.setVariable(key, procVars.get(key));
|
||||
}
|
||||
}
|
||||
|
||||
super.signal(execution, signalName, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main interface method from {@link ActivityBehavior}. It will be called when the BPMN process executes the node referencing this logic.
|
||||
*
|
||||
* @param execution the {@link ActivityExecution} as given to use by the engine
|
||||
* @throws Exception
|
||||
*/
|
||||
public void execute(ActivityExecution execution) throws Exception {
|
||||
String executionId = execution.getId();
|
||||
|
||||
MessageBuilder<?> messageBuilder = MessageBuilder.withPayload(execution).setHeader(ActivitiConstants.WELL_KNOWN_EXECUTION_ID_HEADER_KEY, executionId).setCorrelationId(executionId);
|
||||
|
||||
if (this.forwardProcessVariablesAsMessageHeaders) {
|
||||
Map<String, Object> variables = execution.getVariables();
|
||||
|
||||
if ((variables != null) && (variables.size() > 0)) {
|
||||
messageBuilder = messageBuilder.copyHeadersIfAbsent(variables);
|
||||
}
|
||||
}
|
||||
|
||||
Message<?> msg = messageBuilder.setReplyChannel(replyChannel).build();
|
||||
|
||||
this.messagingTemplate.send(this.requestChannel, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the presence of references to a request and reply {@link org.springframework.integration.MessageChannel},
|
||||
* the {@link ProcessEngine}, and setup the {@link org.springframework.integration.core.MessageHandler} that handles the replies
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(this.replyChannel != null, "'replyChannel' can't be null!");
|
||||
Assert.state(this.requestChannel != null, "'requestChannel' can't be null!");
|
||||
Assert.state(this.processEngine != null, "'processEngine' can't be null!");
|
||||
|
||||
processService = this.processEngine.getRuntimeService();
|
||||
|
||||
if (this.platformTransactionManager != null) {
|
||||
this.messagingTemplate.setTransactionManager(this.platformTransactionManager);
|
||||
}
|
||||
|
||||
MessageHandler handler = new ReplyMessageHandler();
|
||||
|
||||
PollerMetadata pollerMetadata = new PollerMetadata();
|
||||
pollerMetadata.setReceiveTimeout(-1);
|
||||
pollerMetadata.setTransactionManager(this.platformTransactionManager);
|
||||
pollerMetadata.setTrigger(new PeriodicTrigger(10));
|
||||
|
||||
ConsumerEndpointFactoryBean consumerEndpointFactoryBean = new ConsumerEndpointFactoryBean();
|
||||
consumerEndpointFactoryBean.setAutoStartup(false);
|
||||
|
||||
if (this.replyChannel instanceof PollableChannel)
|
||||
consumerEndpointFactoryBean.setPollerMetadata(pollerMetadata);
|
||||
|
||||
consumerEndpointFactoryBean.setBeanFactory(this.beanFactory);
|
||||
consumerEndpointFactoryBean.setHandler(handler);
|
||||
consumerEndpointFactoryBean.setInputChannel(this.replyChannel);
|
||||
consumerEndpointFactoryBean.setBeanName(this.beanName);
|
||||
|
||||
AbstractEndpoint correlator = consumerEndpointFactoryBean.getObject();
|
||||
|
||||
if (correlator != null) {
|
||||
correlator.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanName(String s) {
|
||||
this.beanName = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class listens for results on the reply channel and causes the flow of execution to proceed inside the business process
|
||||
*/
|
||||
class ReplyMessageHandler implements MessageHandler {
|
||||
public void handleMessage(Message<?> message) throws MessageHandlingException, MessageDeliveryException {
|
||||
try {
|
||||
MessageHeaders messageHeaders = message.getHeaders();
|
||||
String executionId = (String) message.getHeaders().get(ActivitiConstants.WELL_KNOWN_EXECUTION_ID_HEADER_KEY);
|
||||
Execution execution = processService.findExecutionById(executionId);
|
||||
processEngine.getRuntimeService().signal(execution.getId(), AsyncActivityBehaviorMessagingGateway.class.getName() , messageHeaders);
|
||||
} catch (Throwable throwable) {
|
||||
throw new RuntimeException(throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti.gateway;
|
||||
|
||||
|
||||
import org.activiti.engine.ProcessEngine;
|
||||
import org.activiti.engine.RuntimeService;
|
||||
import org.activiti.engine.impl.runtime.ExecutionEntity;
|
||||
import org.activiti.engine.runtime.Execution;
|
||||
import org.activiti.pvm.activity.ActivityBehavior;
|
||||
import org.activiti.pvm.activity.ActivityExecution;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.integration.*;
|
||||
import org.springframework.integration.activiti.ActivitiConstants;
|
||||
import org.springframework.integration.activiti.ProcessSupport;
|
||||
import org.springframework.integration.config.ConsumerEndpointFactoryBean;
|
||||
import org.springframework.integration.core.*;
|
||||
import org.springframework.integration.endpoint.AbstractEndpoint;
|
||||
import org.springframework.integration.scheduling.PollerMetadata;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.scheduling.support.PeriodicTrigger;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
/**
|
||||
* This class is plugged into an Activiti workflow. <serviceTask /> let's us plugin a custom {@link ActivityBehavior}.
|
||||
* We need to build an {@link ActivityBehavior} that can send and receive the message,
|
||||
* propagating the {@code executionId} and potentially process variables/ header variables.
|
||||
* <p/>
|
||||
* Simply <code>svn co http://svn.codehaus.org/activiti/activiti/branches/alpha4-spring-integration-adapter</code> that repository and then <code>mvn clean install </code> it.
|
||||
* <p/>
|
||||
* The class forwards ("pushes") control from a BPM process (in-thread) to a Spring Integration channel where, of course, Spring Integration acts as a client and
|
||||
* can push the execution forward anyway it wants to.
|
||||
* <p/>
|
||||
* Possible use cases include forwarding the job through an outbound JMS adapter or gateway, forwarding the job through an XMPP adapter, or forwarding the job through
|
||||
* to an outbound email adapter.
|
||||
* <p/>
|
||||
* <p/>
|
||||
* The only requirement for the reply is that the {@link org.springframework.integration.Message} arrive on the #replyChannel and that it contain a header of
|
||||
* {@link org.springframework.integration.activiti.ActivitiConstants#WELL_KNOWN_EXECUTION_ID_HEADER_KEY} (which the outbound {@link org.springframework.integration.Message} will have)
|
||||
* so that the Activiti runtime can signal that execution has completed successfully.
|
||||
* <p/>
|
||||
* Thanks to Dave Syer and Tom Baeyens for the help brainstorming.
|
||||
* <p/>
|
||||
* This is very much like {@link org.springframework.integration.activiti.gateway.AsyncActivityBehaviorMessagingGateway} except that it assumes that
|
||||
* the request/reply sequence will happen in the same Activiti transaction, so don't keep it waiting! Use the {@link org.springframework.integration.activiti.gateway.AsyncActivityBehaviorMessagingGateway}
|
||||
* which is modeled as a wait-state and deals perfectly with asynchronous continuations.
|
||||
*
|
||||
* @author Josh Long
|
||||
* @see org.activiti.engine.impl.bpmn.ReceiveTaskActivity the {@link org.activiti.pvm.activity.ActivityBehavior} impl that ships w/ Activiti that has the machinery to wake up when signaled
|
||||
* @see org.activiti.engine.ProcessEngine the process engine instance is required to be able to use this namespace
|
||||
* @see org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean - use this class to create the aforementioned ProcessEngine instance!
|
||||
*/
|
||||
public class SyncActivityBehaviorMessagingGateway implements BeanFactoryAware, BeanNameAware, ActivityBehavior, InitializingBean {
|
||||
/**
|
||||
* Used to handle sending in a standard way
|
||||
*/
|
||||
private MessagingTemplate messagingTemplate = new MessagingTemplate();
|
||||
|
||||
/**
|
||||
* This is the channel on which we expect requests - {@link org.activiti.engine.runtime.Execution}s from Activiti - to arrive
|
||||
*/
|
||||
private volatile MessageChannel requestChannel;
|
||||
|
||||
/**
|
||||
* This is the channel on which we expect to send replies - ie, the result of our work in
|
||||
* Spring Integration - back to Activiti, which should be waiting for the results
|
||||
*/
|
||||
private volatile MessageChannel replyChannel;
|
||||
|
||||
/**
|
||||
* Injected from Spring or some other mechanism. Recommended approach is through a {@link org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean}
|
||||
*/
|
||||
private volatile ProcessEngine processEngine;
|
||||
|
||||
/**
|
||||
* Should we update the process variables based on the reply {@link org.springframework.integration.Message}'s {@link org.springframework.integration.MessageHeaders}?
|
||||
*/
|
||||
private volatile boolean updateProcessVariablesFromReplyMessageHeaders = false;
|
||||
|
||||
/**
|
||||
* Should we pass the workflow process variables as message headers when we send a message into the Spring Integration framework?
|
||||
*/
|
||||
private volatile boolean forwardProcessVariablesAsMessageHeaders = false;
|
||||
|
||||
/**
|
||||
* Forwarded to the {@link org.springframework.integration.core.MessagingTemplate} instance.
|
||||
*/
|
||||
private volatile PlatformTransactionManager platformTransactionManager;
|
||||
|
||||
/**
|
||||
* A reference to the {@link org.springframework.beans.factory.BeanFactory} that's hosting this component. Spring will inject this reference automatically assuming
|
||||
* this object is hosted in a Spring context.
|
||||
*/
|
||||
private volatile BeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* The process engine instance that controls the Activiti PVM.
|
||||
*/
|
||||
private RuntimeService runtimeService;
|
||||
|
||||
/**
|
||||
* Provides common logic for things like sifting through inbound message headers and arriving at process variable candidates
|
||||
*/
|
||||
private ProcessSupport processSupport = new ProcessSupport();
|
||||
private String beanName;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setPlatformTransactionManager(PlatformTransactionManager platformTransactionManager) {
|
||||
this.platformTransactionManager = platformTransactionManager;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setRequestChannel(MessageChannel requestChannel) {
|
||||
this.requestChannel = requestChannel;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setReplyChannel(MessageChannel replyChannel) {
|
||||
this.replyChannel = replyChannel;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setProcessEngine(ProcessEngine processEngine) {
|
||||
this.processEngine = processEngine;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setForwardProcessVariablesAsMessageHeaders(boolean forwardProcessVariablesAsMessageHeaders) {
|
||||
this.forwardProcessVariablesAsMessageHeaders = forwardProcessVariablesAsMessageHeaders;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void setUpdateProcessVariablesFromReplyMessageHeaders(boolean updateProcessVariablesFromReplyMessageHeaders) {
|
||||
this.updateProcessVariablesFromReplyMessageHeaders = updateProcessVariablesFromReplyMessageHeaders;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the main interface method from {@link ActivityBehavior}. It will be called when the BPMN process executes the node referencing this logic.
|
||||
*
|
||||
* @param execution the {@link ActivityExecution} as given to use by the engine
|
||||
* @throws Exception
|
||||
*/
|
||||
public void execute(ActivityExecution execution) throws Exception {
|
||||
ExecutionEntity dbExecution = ((ExecutionEntity) execution);
|
||||
String executionId = dbExecution.getId();
|
||||
MessageBuilder<?> messageBuilder = MessageBuilder.withPayload(execution)
|
||||
.setHeader(ActivitiConstants.WELL_KNOWN_EXECUTION_ID_HEADER_KEY, executionId)
|
||||
.setCorrelationId(executionId);
|
||||
|
||||
if (this.forwardProcessVariablesAsMessageHeaders) {
|
||||
Map<String, Object> variables = dbExecution.getVariables();
|
||||
|
||||
if ((variables != null) && (variables.size() > 0)) {
|
||||
messageBuilder = messageBuilder.copyHeadersIfAbsent(variables);
|
||||
}
|
||||
}
|
||||
|
||||
Message<?> msg = messageBuilder.setReplyChannel(replyChannel).build();
|
||||
Message<?> response = this.messagingTemplate.sendAndReceive(requestChannel, msg);
|
||||
|
||||
handleReply(dbExecution, response);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The transaction won't have committed, so there's simply no need to
|
||||
* @param execution the execution
|
||||
* @param msg the inbound message
|
||||
* @throws Exception escape hatch exception
|
||||
*/
|
||||
protected void handleReply(ExecutionEntity execution, Message<?> msg)
|
||||
throws Exception {
|
||||
MessageHeaders messageHeaders = msg.getHeaders();
|
||||
|
||||
if (this.updateProcessVariablesFromReplyMessageHeaders) {
|
||||
Map<String, Object> vars = execution.getVariables();
|
||||
Set<String> existingVars = vars.keySet();
|
||||
Map<String, Object> procVars = this.processSupport.processVariablesFromMessageHeaders(existingVars, messageHeaders);
|
||||
|
||||
for (String varName : procVars.keySet())
|
||||
execution.getProcessInstance().setVariable(varName, procVars.get(varName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify the presence of references to a request and reply {@link MessageChannel},
|
||||
* the {@link ProcessEngine}, and setup the {@link org.springframework.integration.core.MessageHandler} that handles the replies
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.state(this.replyChannel != null, "'replyChannel' can't be null!");
|
||||
Assert.state(this.requestChannel != null, "'requestChannel' can't be null!");
|
||||
Assert.state(this.processEngine != null, "'processEngine' can't be null!");
|
||||
|
||||
runtimeService = this.processEngine.getRuntimeService();
|
||||
|
||||
if (this.platformTransactionManager != null) {
|
||||
this.messagingTemplate.setTransactionManager(this.platformTransactionManager);
|
||||
}
|
||||
|
||||
MessageHandler handler = new ReplyMessageHandler();
|
||||
|
||||
PollerMetadata pollerMetadata = new PollerMetadata();
|
||||
pollerMetadata.setReceiveTimeout(-1);
|
||||
pollerMetadata.setTransactionManager(this.platformTransactionManager);
|
||||
pollerMetadata.setTrigger(new PeriodicTrigger(10));
|
||||
|
||||
ConsumerEndpointFactoryBean consumerEndpointFactoryBean = new ConsumerEndpointFactoryBean();
|
||||
consumerEndpointFactoryBean.setAutoStartup(false);
|
||||
|
||||
if (this.replyChannel instanceof PollableChannel) {
|
||||
consumerEndpointFactoryBean.setPollerMetadata(pollerMetadata);
|
||||
}
|
||||
|
||||
consumerEndpointFactoryBean.setBeanFactory(this.beanFactory);
|
||||
consumerEndpointFactoryBean.setHandler(handler);
|
||||
consumerEndpointFactoryBean.setInputChannel(this.replyChannel);
|
||||
consumerEndpointFactoryBean.setBeanName(this.beanName);
|
||||
|
||||
AbstractEndpoint correlator = consumerEndpointFactoryBean.getObject();
|
||||
|
||||
if (correlator != null) {
|
||||
correlator.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void setBeanName(String s) {
|
||||
this.beanName = s;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class listens for results on the reply channel and causes the flow of execution to proceed inside the business process
|
||||
*/
|
||||
class ReplyMessageHandler implements MessageHandler {
|
||||
public void handleMessage(Message<?> message) throws MessageHandlingException, MessageDeliveryException {
|
||||
try {
|
||||
MessageHeaders messageHeaders = message.getHeaders();
|
||||
String executionId = (String) message.getHeaders().get(ActivitiConstants.WELL_KNOWN_EXECUTION_ID_HEADER_KEY);
|
||||
Execution execution = runtimeService.findExecutionById(executionId);
|
||||
processEngine.getRuntimeService().signal(execution.getId(), StringUtils.EMPTY, messageHeaders);
|
||||
} catch (Throwable throwable) {
|
||||
throw new RuntimeException(throwable);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
http\://www.springframework.org/schema/integration/activiti=org.springframework.integration.activiti.config.ActivitiNamespaceHandler
|
||||
@@ -0,0 +1,2 @@
|
||||
http\://www.springframework.org/schema/integration/activiti/spring-integration-activiti-2.0.xsd=org/springframework/integration/activiti/config/spring-integration-activiti-2.0.xsd
|
||||
http\://www.springframework.org/schema/integration/activiti/spring-integration-activiti.xsd=org/springframework/integration/activiti/config/spring-integration-activiti-2.0.xsd
|
||||
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2010 the original author or authors
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
|
||||
<xsd:schema xmlns="http://www.springframework.org/schema/integration/activiti"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:tool="http://www.springframework.org/schema/tool"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
targetNamespace="http://www.springframework.org/schema/integration/activiti"
|
||||
elementFormDefault="qualified"
|
||||
attributeFormDefault="unqualified">
|
||||
|
||||
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
|
||||
<xsd:import namespace="http://www.springframework.org/schema/integration" schemaLocation="http://www.springframework.org/schema/integration/spring-integration-2.0.xsd"/>
|
||||
|
||||
|
||||
<!--
|
||||
outbound adapter
|
||||
-->
|
||||
<xsd:element name="outbound-channel-adapter">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
|
||||
Builds an outbound-channel-adapter that writes files to a remote FTP endpoint.
|
||||
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="id" type="xsd:string"/>
|
||||
<xsd:attribute name="channel" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="process-engine" use="required" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.activiti.ProcessEngine"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
<xsd:attribute name="process-definition-name" type="xsd:string"/>
|
||||
|
||||
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="inbound-gateway">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
|
||||
Defines an inbound Activiti Messaging Gateway.
|
||||
|
||||
This bean should be referenced from a BPMN workflow artifact. Once entered, execution of the task will be dispatched to Spring Integration
|
||||
where Spring Integration can then do whatever it likes so long as execution ultimately travels through the 'reply-channel'.
|
||||
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="update-process-variables-from-reply-message-headers" type="xsd:boolean"/>
|
||||
<xsd:attribute name="async" type="xsd:boolean"/>
|
||||
<xsd:attribute name="forward-process-variables-as-message-headers" type="xsd:boolean"/>
|
||||
<xsd:attribute name="request-channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="reply-channel" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.integration.core.MessageChannel"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="process-engine" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.activiti.ProcessEngine"/>
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
</xsd:schema>
|
||||
@@ -0,0 +1,48 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti;
|
||||
|
||||
import org.activiti.engine.ProcessEngine;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
|
||||
/**
|
||||
* This component demonstrates creating a {@link org.springframework.integration.activiti.gateway.AsyncActivityBehaviorMessagingGateway} (factoried from Spring)
|
||||
* and exposed for use in a BPMN 2 process.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class GatewayTest extends AbstractJUnit4SpringContextTests {
|
||||
|
||||
@Autowired private ProcessEngine processEngine ;
|
||||
|
||||
@Test
|
||||
public void testGateway() throws Throwable {
|
||||
processEngine.getRepositoryService().createDeployment().addClasspathResource("processes/si_gateway_example.bpmn20.xml").deploy();
|
||||
Map<String, Object> vars = new HashMap<String, Object>();
|
||||
vars.put("customerId", 232);
|
||||
processEngine.getRuntimeService().startProcessInstanceByKey("sigatewayProcess", vars);
|
||||
Thread.sleep(10000);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.integration.activiti;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.integration.MessageChannel;
|
||||
import org.springframework.integration.core.MessagingTemplate;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
|
||||
public class OutboundAdapterTest {
|
||||
|
||||
|
||||
@Value( "#{tc}")
|
||||
private MessageChannel messageChannel ;
|
||||
|
||||
private MessagingTemplate messagingTemplate = new MessagingTemplate();
|
||||
|
||||
@Test
|
||||
public void testOutboundAdapter() throws Throwable {
|
||||
this.messagingTemplate.send( this.messageChannel , MessageBuilder.withPayload( "hello, from "+ System.currentTimeMillis())
|
||||
.setHeader( ActivitiConstants.WELL_KNOWN_PROCESS_DEFINITION_NAME_HEADER_KEY+"customerId",2324).build());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti.impls;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
|
||||
|
||||
public class AnnouncingServiceActivator {
|
||||
@ServiceActivator
|
||||
public void hello(Message<?> msg) throws Throwable {
|
||||
System.out.println("got it ");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti.impls;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.activiti.ActivitiConstants;
|
||||
import org.springframework.integration.annotation.ServiceActivator;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
|
||||
|
||||
/**
|
||||
* This is a trivial component that demonstrates that the flow of control lives outside of the BPMN process (ie, that we have truly implemented a wait-state)
|
||||
* and that gateway does the right thing if you send back message headers whose key corresponds with process variables, or new message headers that you want as process variables.
|
||||
* <p/>
|
||||
* The only requirement for any component wishing to reply to an Activiti business process is that there be a header named using the static variable
|
||||
* {@link org.springframework.integration.activiti.ActivitiConstants#WELL_KNOWN_EXECUTION_ID_HEADER_KEY}.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class DelayedchoServiceActivator {
|
||||
|
||||
@ServiceActivator
|
||||
public Message<?> sayHello(Message<?> requestComingFromActiviti)
|
||||
throws Throwable {
|
||||
System.out.println("entering ServiceActivator:sayHello");
|
||||
Thread.sleep(5 * 1000);
|
||||
System.out.println("exiting ServiceActivator:sayHello");
|
||||
return MessageBuilder.withPayload(requestComingFromActiviti.getPayload()).
|
||||
copyHeadersIfAbsent(requestComingFromActiviti.getHeaders()).setHeader(
|
||||
ActivitiConstants.WELL_KNOWN_SPRING_INTEGRATION_HEADER_PREFIX + "test", "1 + 1").
|
||||
build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti.impls;
|
||||
|
||||
import org.activiti.engine.impl.runtime.ExecutionEntity;
|
||||
|
||||
import org.activiti.pvm.activity.ActivityBehavior;
|
||||
import org.activiti.pvm.activity.ActivityExecution;
|
||||
import org.activiti.pvm.process.PvmTransition;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* A simple component that implements {@link ActivityBehavior}
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class SimpleCustomActivityBehavior implements ActivityBehavior, InitializingBean {
|
||||
public void execute(ActivityExecution dbExecution)
|
||||
throws Exception {
|
||||
System.out.println("Hello from a custom ActivityBehavior hosted in the Spring context. " + this);
|
||||
|
||||
|
||||
for (String varName : dbExecution.getVariables().keySet())
|
||||
System.out.println(varName + "=" + dbExecution.getVariable(varName));
|
||||
|
||||
|
||||
List<PvmTransition> transitions = dbExecution.getActivity().getOutgoingTransitions();
|
||||
|
||||
dbExecution.take(((null == transitions) || (transitions.size() == 0)) ? null : transitions.get(0));
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
System.out.println("Starting " + SimpleCustomActivityBehavior.class.getName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.integration.activiti.impls;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.activiti.ActivitiConstants;
|
||||
import org.springframework.integration.core.MessageSource;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
|
||||
|
||||
/**
|
||||
* Triggers a BPMN process that has process variables.
|
||||
*
|
||||
* @author Josh Long
|
||||
*/
|
||||
public class SimpleProcessTriggeringMessageSource implements MessageSource<String> {
|
||||
|
||||
private final Log logger = LogFactory.getLog(SimpleProcessTriggeringMessageSource.class.getName());
|
||||
|
||||
public Message<String> receive() {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
logger.debug("couldn't sleep 1000 ms", e);
|
||||
}
|
||||
return MessageBuilder.withPayload(
|
||||
"hello from " + System.currentTimeMillis()
|
||||
).
|
||||
setHeader(ActivitiConstants.WELL_KNOWN_SPRING_INTEGRATION_HEADER_PREFIX + "customerId", 232).
|
||||
setHeader( ActivitiConstants.WELL_KNOWN_PROCESS_DEFINITION_NAME_HEADER_KEY, "helloWorldProcess" ).build();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:activiti="http://www.springframework.org/schema/integration/activiti"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/integration/activiti http://www.springframework.org/schema/integration/activiti/spring-integration-activiti-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
">
|
||||
|
||||
<!--
|
||||
==========================================================
|
||||
Context Globals
|
||||
==========================================================
|
||||
-->
|
||||
|
||||
<context:annotation-config/>
|
||||
|
||||
<int:poller default="true">
|
||||
<int:interval-trigger interval="1000"/>
|
||||
</int:poller>
|
||||
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
|
||||
<property name="targetDataSource">
|
||||
<bean class="org.apache.commons.dbcp.BasicDataSource"
|
||||
p:url="jdbc:h2:tcp://localhost/~/activiti_example"
|
||||
p:driverClassName="org.h2.Driver"
|
||||
p:username="sa"
|
||||
p:password=""
|
||||
/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
|
||||
p:dataSource-ref="dataSource"/>
|
||||
|
||||
<bean id="processEngine" class="org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean"
|
||||
p:dataSource-ref="dataSource"
|
||||
p:transactionManager-ref="transactionManager"
|
||||
p:dbSchemaStrategy="DROP_CREATE"
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
==========================================================
|
||||
Spring Integration Flow
|
||||
==========================================================
|
||||
-->
|
||||
|
||||
<!-- Activiti sends a message 'to' (inbound) Spring Integration 'from' Activiti -->
|
||||
<activiti:inbound-gateway
|
||||
process-engine="processEngine"
|
||||
request-channel="request"
|
||||
async="true"
|
||||
reply-channel="response"
|
||||
forward-process-variables-as-message-headers="true"
|
||||
update-process-variables-from-reply-message-headers="true"
|
||||
id="gateway"
|
||||
/>
|
||||
|
||||
<!-- the message comes 'into' Spring Integration from 'request' channel -->
|
||||
<int:channel id="request">
|
||||
<int:queue capacity="10"/>
|
||||
</int:channel>
|
||||
|
||||
<!-- where the service activator eventually reads the request channel and does some processing
|
||||
(though, of course, this may as well have been a JMS adapter or an email adapter). Finally the response is created and sent on..
|
||||
-->
|
||||
<bean id="echoServiceActivator" class="org.springframework.integration.activiti.impls.DelayedchoServiceActivator"/>
|
||||
|
||||
<int:service-activator input-channel="request" ref="echoServiceActivator" output-channel="response"/>
|
||||
|
||||
<!--the response channel -->
|
||||
<int:channel id="response"/>
|
||||
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xmlns:activiti="http://www.springframework.org/schema/integration/activiti"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/integration/activiti http://www.springframework.org/schema/integration/activiti/spring-integration-activiti-2.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
|
||||
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-3.0.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
">
|
||||
|
||||
<!--
|
||||
==========================================================
|
||||
Context Globals
|
||||
==========================================================
|
||||
-->
|
||||
|
||||
<context:annotation-config/>
|
||||
|
||||
<int:poller default="true">
|
||||
<int:interval-trigger interval="1000"/>
|
||||
</int:poller>
|
||||
|
||||
<bean id="dataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
|
||||
<property name="targetDataSource">
|
||||
<bean class="org.apache.commons.dbcp.BasicDataSource"
|
||||
p:url="jdbc:h2:tcp://localhost/~/activiti_example"
|
||||
p:driverClassName="org.h2.Driver"
|
||||
p:username="sa"
|
||||
p:password=""
|
||||
/>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
|
||||
p:dataSource-ref="dataSource"/>
|
||||
|
||||
<bean id="processEngine" class="org.activiti.engine.impl.cfg.spring.ProcessEngineFactoryBean"
|
||||
p:dataSource-ref="dataSource"
|
||||
p:transactionManager-ref="transactionManager"
|
||||
p:dbSchemaStrategy="DROP_CREATE"
|
||||
>
|
||||
|
||||
<property name="deploymentResources">
|
||||
<array>
|
||||
<value>classpath:/processes/hello-world.bpmn20.xml</value>
|
||||
</array>
|
||||
</property>
|
||||
|
||||
</bean>
|
||||
|
||||
<bean lazy-init="true" class="org.springframework.integration.activiti.impls.SimpleCustomActivityBehavior" id="activityBehavior"/>
|
||||
|
||||
|
||||
<!--
|
||||
==========================================================
|
||||
Spring Integration Flow
|
||||
==========================================================
|
||||
-->
|
||||
|
||||
<!-- Activiti sends a message 'to' (inbound) Spring Integration 'from' Activiti -->
|
||||
|
||||
<bean class="org.springframework.integration.activiti.impls.AnnouncingServiceActivator" id="activator"/>
|
||||
|
||||
|
||||
<int:channel id="tc">
|
||||
<int:queue capacity="100"/>
|
||||
</int:channel>
|
||||
|
||||
<activiti:outbound-channel-adapter channel="tc" process-engine="processEngine" process-definition-name="helloWorldProcess"/>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions id="definitions"
|
||||
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:activiti="http://activiti.org/bpmn-extensions"
|
||||
typeLanguage="http://www.w3.org/2001/XMLSchema"
|
||||
expressionLanguage="http://www.w3.org/1999/XPath"
|
||||
targetNamespace="http://www.activiti.org/bpmn2.0">
|
||||
|
||||
<process id="helloWorldProcess">
|
||||
|
||||
<startEvent id="theStart"/>
|
||||
|
||||
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="ab"/>
|
||||
|
||||
<serviceTask id="ab" name="Simple POJO delegation" activiti:class="#{activityBehavior}"/>
|
||||
|
||||
<sequenceFlow id="flow2" sourceRef="ab" targetRef="theEnd"/>
|
||||
|
||||
<endEvent id="theEnd"/>
|
||||
|
||||
</process>
|
||||
|
||||
</definitions>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<definitions id="definitions"
|
||||
xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:activiti="http://activiti.org/bpmn-extensions"
|
||||
typeLanguage="http://www.w3.org/2001/XMLSchema"
|
||||
expressionLanguage="http://www.w3.org/1999/XPath"
|
||||
targetNamespace="http://www.activiti.org/bpmn2.0">
|
||||
|
||||
<process id="sigatewayProcess">
|
||||
|
||||
<startEvent id="theStart"/>
|
||||
|
||||
<sequenceFlow id="flow1" sourceRef="theStart" targetRef="sigw"/>
|
||||
|
||||
<serviceTask id="sigw" name="Spring Integration Gateway" activiti:class="#{gateway}"/>
|
||||
|
||||
<sequenceFlow id="flow2" sourceRef="sigw" targetRef="theEnd"/>
|
||||
|
||||
<endEvent id="theEnd"/>
|
||||
|
||||
</process>
|
||||
|
||||
</definitions>
|
||||
15
spring-integration-activiti/template.mf
Normal file
15
spring-integration-activiti/template.mf
Normal file
@@ -0,0 +1,15 @@
|
||||
Bundle-SymbolicName: org.springframework.integration.activiti
|
||||
Bundle-Name: Spring Integration Activiti Support
|
||||
Bundle-Vendor: SpringSource
|
||||
Bundle-ManifestVersion: 2
|
||||
Import-Template:
|
||||
org.apache.commons.logging;version="[1.1.1, 2.0.0)",
|
||||
org.apache.commons.lang.*;version="[2.5.0, 3.0.0)",
|
||||
org.springframework.integration.*;version="[2.0.0, 2.0.1)",
|
||||
org.springframework.beans.*;version="[3.0.0, 4.0.0)",
|
||||
org.springframework.context;version="[3.0.0, 4.0.0)",
|
||||
org.springframework.core.*;version="[3.0.0, 4.0.0)",
|
||||
org.springframework.util;version="[3.0.0, 4.0.0)",
|
||||
org.jivesoftware.*;version="[3.1.0, 4.0.0)",
|
||||
javax.*;version="0",
|
||||
org.w3c.dom.*;version="0"
|
||||
@@ -82,6 +82,7 @@
|
||||
<include>org.springframework.integration:spring-integration-sftp</include>
|
||||
<include>org.springframework.integration:spring-integration-ftp</include>
|
||||
<include>org.springframework.integration:spring-integration-twitter</include>
|
||||
<include>org.springframework.integration:spring-integration-activiti</include>
|
||||
</includes>
|
||||
<binaries>
|
||||
<outputDirectory>dist</outputDirectory>
|
||||
|
||||
Reference in New Issue
Block a user