I have a situation with my spring integration with rabbitmq. The messages are sent to the queues but end up in the ready state and one as unacknowledged but the consumer doesn't gets them.
Thx xml configuration is like this:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-amqp="http://www.springframework.org/schema/integration/amqp"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/amqp
http://www.springframework.org/schema/integration/amqp/spring-integration-amqp.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:spring/prj-rabbitmq-context-thirdparty.properties" ignore-unresolvable="true" order="3"/>
<rabbit:connection-factory
id="prjRabbitmqConnectionFactory"
addresses="${rabbitmq.addresses}"
username="${rabbitmq.username}"
password="${rabbitmq.password}"
connection-timeout="5000" />
<bean id="rabbitTxManager"
class="org.springframework.amqp.rabbit.transaction.RabbitTransactionManager">
<property name="connectionFactory" ref="prjRabbitmqConnectionFactory"/>
</bean>
<rabbit:template
id="prjRabbitmqTemplate"
connection-factory="prjRabbitmqConnectionFactory"
message-converter="serializerMessageConverter"
retry-template="retryTemplate" />
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="1000" />
<property name="multiplier" value="3" />
<property name="maxInterval" value="10000" />
</bean>
</property>
</bean>
<rabbit:admin
id="prjRabbitmqAdmin"
auto-startup="true"
connection-factory="prjRabbitmqConnectionFactory" />
<rabbit:queue
id="prjSyncQueue"
name="${prj.sync.queue}"
durable="true">
<rabbit:queue-arguments>
<entry key="x-ha-policy" value="all" />
</rabbit:queue-arguments>
</rabbit:queue>
<rabbit:listener-container
connection-factory="prjRabbitmqConnectionFactory"
acknowledge="auto"
channel-transacted="true"
transaction-manager="rabbitTxManager"
task-executor="prjSyncExecutor"
concurrency="1"
max-concurrency="2"
requeue-rejected="true"
message-converter="serializerMessageConverter">
<rabbit:listener
ref="prjProcessorService"
queue-names="${prj.sync.queue}" method="processMessage" />
</rabbit:listener-container>
<task:executor id="prjSyncExecutor"
pool-size="${prj.sync.concurrency.min}-${prj.sync.concurrency.max}"
keep-alive="${prj.sync.concurrency.keep-alive}"
queue-capacity="${prj.sync.concurrency.queue}"
rejection-policy="CALLER_RUNS"/>
<int:channel
id="prjChannel" />
<int-amqp:outbound-channel-adapter
channel="prjChannel"
amqp-template="prjRabbitmqTemplate"
exchange-name="prjSyncExchange"
routing-key="prj-event"
default-delivery-mode="PERSISTENT" />
<rabbit:direct-exchange
name="prjSyncExchange">
<rabbit:bindings>
<rabbit:binding
queue="prjSyncQueue"
key="prj-event" />
</rabbit:bindings>
</rabbit:direct-exchange>
<int:gateway
id="prjGateway"
service-interface="ro.oss.niinoo.thirdparty.prj.gateway.prjEnrichmentGateway">
<int:method
name="send"
request-channel="prjChannel"/>
</int:gateway>
<bean id="prjProcessorService" class="ro.oss.niinoo.thirdparty.prj.processor.impl.prjEnrichmentProcessorImpl" />
<bean id="serializerMessageConverter" class="ro.oss.niinoo.thirdparty.prj.serializer.prjSerializer"/>
On the server restart the first one is picked up but on the next call the messages piles up in the queue. Do you have any idea why this might happen ?
Thanks
Daniel
EDIT:
The consumer code:
public class JsonEnrichmentService implements EnrichmentService {
#Resource
private UserQueryService userQueryService;
#Resource
private SecurityContextService securityContextService;
#Override
public void processMessage(POJO record) {
System.out.println(record);
}
This will call a new service that has a Transactional annotation to it.
In my experience, this is generally caused by the listener thread being "stuck" in user code someplace. Take a thread dump to see what the listener thread is doing.
Related
I have started using Spring-integration for listening on JMS-queues, and it's working satisfactory, but I have somewhat of an issue with the amount of xml-configuration required in order to set up a listener. Most of this is boilerplate, what changes is really just the jms-instance and the name of the queue to listen to, and the class and method to invoke upon receiving a message. Here is an example:
<?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:int="http://www.springframework.org/schema/integration"
xmlns:jms="http://www.springframework.org/schema/integration/jms"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
<bean id="jms.queue.myQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="${myApplication.jms.queue.myQueue}" />
</bean>
<bean id="jms.container.myJMSListender"
class="org.springframework.jms.listener.DefaultMessageListenerContainer"
destroy-method="destroy">
<property name="connectionFactory"
ref="jmsConnectionFactory" /> <!-- Defined elsewhere -->
<property name="destination"
ref="jms.queue.myQueue" />
<property name="sessionTransacted"
value="true" />
</bean>
<int:publish-subscribe-channel id="channel.myQueue" />
<jms:message-driven-channel-adapter id="channelAdapter.myQueue"
container="jms.container.myQueue"
channel="channel.myQueue"
acknowledge="transacted"/>
<int:service-activator id="serviceActivator.myQueue"
input-channel="channgel.myQueue"
ref="myQueueJMSListener"
method="handleMessage" />
</beans>
As you can see, a lot of config for something fairly simple, and with quite a lot of JMS-listeners this becomes tedious, both to read and write.
Is there a way to configure listening to a queue with Spring-integration that requires less boilerplate? I've looked into creating my own XML-tag, but I'm kinda hoping that there is a simpler solution.
You only need an external container if you need to configure properties that are not exposed on the namespace.
<jms:message-driven-channel-adapter id="channelAdapter.myQueue"
destination="jms.queue.myQueue"
connection-factory="jmsConnectionFactory"
channel="channel.myQueue"
acknowledge="transacted"/>
Found that Spring integration has annotation support.
Requires some setup, but this can be used for multiple listeners:
<amq:connectionFactory id="jmsConnectionFactory" brokerURL="${jms.host}">
<amq:redeliveryPolicy>
<amq:redeliveryPolicy maximumRedeliveries="0" />
</amq:redeliveryPolicy>
</amq:connectionFactory>
<bean id="cachingJmsConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsConnectionFactory" />
</bean>
<jms:annotation-driven />
<bean id="jmsListenerContainerFactory" class="org.springframework.jms.config.DefaultJmsListenerContainerFactory">
<property name="connectionFactory" ref="cachingJmsConnectionFactory" />
</bean>
Then, listening to a certain queue is as simple as:
#JmsListener(destination = "${myQueueName}")
public void listen(#Payload final String payload) {
I am trying to use the example project of Spring-Integration JMS for JMS integration, Which I have done succesfully. How ever I have a slightly different set of requirement. Where I need to listen from 1 JMS Broker using Publish Subscribe pattern and, I need to send the same listened JMS message to another Kafak Queue/or nay other queue. I am struggling with the configuration, as of now I have configured only for request and response queue. Here are the configuration. Please help.
Common.xml
<?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:integration="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd">
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost"/>
</bean>
</property>
<property name="sessionCacheSize" value="10"/>
<property name="cacheProducers" value="false"/>
</bean>
<!-- <bean id="requestQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue.demo"/>
</bean> -->
<bean id="replyQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue.reply"/>
</bean>
<bean id="requestQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue.request"/>
</bean>
<integration:poller id="poller" default="true" fixed-delay="100"/>
</beans>
InboudChanelAdapter
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:jms="http://www.springframework.org/schema/integration/jms"
xmlns:stream="http://www.springframework.org/schema/integration/stream"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/integration/stream
http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd">
<jms:message-driven-channel-adapter id="jmsIn"
destination="requestQueue"
channel="jmsInChannel" />
<channel id="jmsInChannel" />
<beans:beans profile="testCase">
<bridge input-channel="jmsInChannel" output-channel="queueChannel"/>
<channel id="queueChannel">
<queue />
</channel>
</beans:beans>
</beans:beans>
OutboundChannelAdapter.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:jms="http://www.springframework.org/schema/integration/jms"
xmlns:stream="http://www.springframework.org/schema/integration/stream"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd
http://www.springframework.org/schema/integration/stream
http://www.springframework.org/schema/integration/stream/spring-integration-stream.xsd">
<stream:stdin-channel-adapter id="stdin" channel="stdinToJmsoutChannel"/>
<channel id="stdinToJmsoutChannel"/>
<channel id="jmsInChannel" />
<jms:outbound-channel-adapter id="jmsout" channel="jmsInChannel" destination="requestQueue"/>
</beans:beans>
**DemoConfig.xml**
<?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:integration="http://www.springframework.org/schema/integration"
xmlns:jms="http://www.springframework.org/schema/integration/jms"
xmlns:beans="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration
http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/jms
http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd">
<bean id="connectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost"/>
</bean>
</property>
<property name="sessionCacheSize" value="10"/>
<property name="cacheProducers" value="false"/>
</bean>
<bean id="connectionFactory2nd" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory">
<bean class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost"/>
</bean>
</property>
<property name="sessionCacheSize" value="10"/>
<property name="cacheProducers" value="false"/>
</bean>
<bean id="replyQueue" class="org.apache.activemq.command.ActiveMQQueue" >
<constructor-arg value="queue.reply"/>
</bean>
<bean id="requestQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="queue.request"/>
</bean>
<jms:message-driven-channel-adapter id="jmsIn"
destination="requestQueue"
channel="jmsInChannel"
connection-factory="connectionFactory"/>
<jms:publish-subscribe-channel id= "jmsInChannel"/>
<jms:topic id="Topic"></jms:topic>
</<jms:channel>
<jms:outbound-channel-adapter id="jmsout" channel="jmsInChannel" destination="replyQueue" connection-factory="connectionFactory2nd"/>
<integration:poller id="poller" default="true" fixed-delay="100"/>
</beans>
Looks like you don't have enough theoretical knowledge, so you should go to the Docs and Books about Spring Integration. You don't feel well what is MessageChannel yet.
<jms:message-driven-channel-adapter id="jmsIn"
destination="requestQueue"
channel="jmsInChannel" />
Means: listen on the requestQueue destination and send the Spring Integration Message to the jmsInChannel.
If you are going just to send that message to the another JMS destination you should do something like this:
<jms:outbound-channel-adapter id="jmsout" channel="jmsInChannel" destination="replyQueue"/>
And be sure that there is no more subscriber to that jmsInChannel, because it is a DirectChannel.
According to your current config you have additional subscriber as <bridge>. In this case the Round-Robin balancer works on that jmsInChannel and the first message will be sent to the first subscriber, and only the second - to the second, and so on.
If you want accept that message by both subscribers you should change jmsInChannel to the <publish-subscribe-channel>.
More info you can find from docs.
I'm using Spring JMS and ActiveMQ where I have a client that pushes messages to a Queue and I have multiple consumer threads that are listening and removing messages from the Queue. Some of the time the same messages gets dequeued from the Queue by two consumers. I don't want this behavior and want to ensure the only one messages is processed by only one consumer thread. Any ideas on where I've gone wrong?
Spring 3.2.2 Config:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<context:annotation-config />
<context:component-scan base-package="com.myapp" />
<!-- JMS ConnectionFactory config Starts -->
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>${brokerURL}</value>
</property>
<property name="userName" value="${username}" />
<property name="password" value="${password}" />
</bean>
<bean id="pooledJmsConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory"
init-method="start" destroy-method="stop">
<property name="connectionFactory" ref="jmsConnectionFactory" />
</bean>
<!-- JMS ConnectionFactory config Ends -->
<!-- JMS Template config Starts -->
<bean id="myQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg value="${activemq.consumer.destinationName}" />
</bean>
<bean id="myQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="pooledJmsConnectionFactory" />
</bean>
<!-- JMS Template config Ends -->
<!-- JMS Listener config starts -->
<bean id="simpleMessageConverter"
class="org.springframework.jms.support.converter.SimpleMessageConverter" />
<bean id="myContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="${threadcount}" />
<property name="connectionFactory" ref="pooledJmsConnectionFactory" />
<property name="destination" ref="myQueue" />
<property name="messageListener" ref="myListener" />
<property name="messageSelector" value="JMSType = 'New'" />
</bean>
<bean id="myListener"
class="org.springframework.jms.listener.adapter.MessageListenerAdapter">
<constructor-arg>
<bean class="myapp.MessageListener" />
</constructor-arg>
<property name="defaultListenerMethod" value="receive" />
<property name="messageConverter" ref="simpleMessageConverter" />
</bean>
<!-- JMS Listener config Ends -->
<!-- enable the configuration of transactional behavior based on annotations -->
<bean id="myJMSMessageSender" class="myapp.JMSMessageSender">
<property name="jmsTemplate" ref="myQueueTemplate" />
<property name="jmsQueue" ref="myQueue" />
<property name="messageConverter" ref="simpleMessageConverter" />
</bean>
<bean id="myQueueTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="pooledJmsConnectionFactory" />
</bean>
</beans>
ActiveMQ 5.9.1 config:
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="instance8161" dataDirectory="${activemq.data}" persistent="false">
<destinationPolicy>
<policyMap>
<policyEntries>
<policyEntry topic=">">
<!-- The constantPendingMessageLimitStrategy is used to prevent
slow topic consumers to block producers and affect other consumers
by limiting the number of messages that are retained
For more information, see:
http://activemq.apache.org/slow-consumer-handling.html
-->
<pendingMessageLimitStrategy>
<constantPendingMessageLimitStrategy limit="1000"/>
</pendingMessageLimitStrategy>
</policyEntry>
</policyEntries>
</policyMap>
</destinationPolicy>
... <!-- rest is default ActiveMQ Config -->
</broker>
Most likely, your myapp.MessageListener (or one of its dependencies) is not thread-safe and you are seeing cross-talk across the consumer threads.
Best practice is to craft your listener as stateless (no mutated fields in the class). If that's not possible, you need to protect shared variables with locks.
I am working on a POC to design workflow for our company. we heavily use ActiveMQ in our system. I am working on integrating activiti and camel routes that has activeMQ queues inside it.when I run the process, it goes through the camel route containing the queues and creates the new queues but the messages is not passed from one queue to another.
I get this following message on the target queue:
Unknown message type [org.apache.activemq.command.ActiveMQMessage] ActiveMQMessage
below is the stack trace:
2:11:59.705 [Camel (camelContext) thread #0 - JmsConsumer[TESTQUEUE]] WARN o.a.c.c.jms.EndpointMessageListener - Execution of JMS message listener failed. Caused by: [org.apache.camel.RuntimeCamelException - org.activiti.engine.ActivitiIllegalArgumentException: Business key is null]
org.apache.camel.RuntimeCamelException: org.activiti.engine.ActivitiIllegalArgumentException: Business key is null
at org.apache.camel.util.ObjectHelper.wrapRuntimeCamelException(ObjectHelper.java:1363) ~[camel-core-2.13.2.jar:2.13.2]
at org.apache.camel.component.jms.EndpointMessageListener$EndpointMessageListenerAsyncCallback.done(EndpointMessageListener.java:186) ~[camel-jms-2.13.1.jar:2.13.1]
at org.apache.camel.component.jms.EndpointMessageListener.onMessage(EndpointMessageListener.java:107) ~[camel-jms-2.13.1.jar:2.13.1]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doInvokeListener(AbstractMessageListenerContainer.java:562) ~[spring-jms-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeListener(AbstractMessageListenerContainer.java:500) ~[spring-jms-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.jms.listener.AbstractMessageListenerContainer.doExecuteListener(AbstractMessageListenerContainer.java:468) ~[spring-jms-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:325) [spring-jms-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:263) [spring-jms-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1101) [spring-jms-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1093) [spring-jms-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:990) [spring-jms-3.2.8.RELEASE.jar:3.2.8.RELEASE]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_40]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_40]
at java.lang.Thread.run(Thread.java:724) [na:1.7.0_40]
Caused by: org.activiti.engine.ActivitiIllegalArgumentException: Business key is null
Here is my camelRoute.bpmn file:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:activiti="http://activiti.org/bpmn"
xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI"
xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC"
xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI"
typeLanguage="http://www.w3.org/2001/XMLSchema"
expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.activiti.org/test">
<process id="SimpleCamelCallProcess" isExecutable="true">
<startEvent id="start"/>
<sequenceFlow id="flow1" sourceRef="start" targetRef="simpleCall"/>
<serviceTask id="simpleCall" activiti:type="camel"/>
<sequenceFlow id="flow2" sourceRef="simpleCall" targetRef="end"/>
<endEvent id="end"/>
</process>
</definitions>
Below is my camel route calling the bpmn:
public class CamelHelloRoute extends RouteBuilder {
private static final Logger logger = LoggerFactory.getLogger(CamelHelloRoute.class);
#Override
public void configure() throws Exception {
from("activemq:queue:TESTQUEUE")
.log(LoggingLevel.INFO, "Received message ")
.to("activiti:SimpleCamelCallProcess:simpleCall");
from("activiti:SimpleCamelCallProcess:simpleCall")
.log(LoggingLevel.INFO, "Received message on service task ")
.to("activemq:queue:TESTQUEUE3");
}
}
Below is my junit class:
public class ProcessTestSimpleCamelCallProcess {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("camel-int.xml");
#Rule
public ActivitiRule activitiRule= (ActivitiRule) applicationContext.getBean("activitiRule");
public RepositoryService repositoryService=(RepositoryService) applicationContext.getBean("repositoryService");
#Test
public void startProcess() throws Exception {
repositoryService = activitiRule.getRepositoryService();
repositoryService.createDeployment().addClasspathResource("camelRoute.bpmn").deploy();
RuntimeService runtimeService = activitiRule.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("SimpleCamelCallProcess");
assertNotNull(processInstance.getId());
System.out.println("id " + processInstance.getId() + " "
+ processInstance.getProcessDefinitionId());
}
Below is my spring file "camel-int.xml":
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring-2.13.2.xsd">
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/workflowtest"></property>
<property name="username" value="root"></property>
<property name="password" value="abc123"></property>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseSchemaUpdate" value="true" />
<property name="jobExecutorActivate" value="false" />
</bean>
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration" />
</bean>
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />
<bean id="managementService" factory-bean="processEngine" factory-method="getManagementService" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="activitiRule" class="org.activiti.engine.test.ActivitiRule">
<property name="processEngine" ref="processEngine" />
</bean>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
<camelContext id="camelContext" xmlns="http://camel.apache.org/schema/spring">
<packageScan>
<package>com.activiti.camel</package>
</packageScan>
</camelContext>
</beans>
I have a simple Hello World example that passes a Map to Camel and displays the values to the console via Log4J. I want to expand this example to render this map in JSON by adding the Jackson library to my Camel applicationContext.xml
First I tried adding the following XML tags to my applicationContext.xml (as specified at
http://camel.apache.org/json.html under "Using JSON in Spring DSL")
<camel:dataFormats>
<camel:json id="jack" library="Jackson"/>
</camel:dataFormats>
But when I add this to my applicationContext.xml, and run my Java code I get the following XmlBeanDefinitionStoreException message:
cvc-complex-type.2.4.a: Invalid content was found starting with element 'dataFormats'. One of '{"http://camel.apache.org/schema/
spring":route}' is expected.
Moving these tags inside or outside of my camelContext yields the same error (just a longer list of URLs when inside the camelContext).
Is there something else I need to specify in my ApplicationContext.xml?
Here is my current applicationContext.xml:
UPDATED: The following xml now works. Had to move the location of the dataFormats XML tags.
<?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:camel="http://camel.apache.org/schema/spring"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean
class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
<context:component-scan base-package="sample" />
<context:annotation-config />
<camel:camelContext id="HelloWorldContext">
<camel:dataFormats>
<camel:json id="jack" library="Jackson"/>
</camel:dataFormats>
<camel:route>
<camel:from
uri="timer://hello.world.request.timer?fixedRate=true&period=10000" />
<camel:to uri="log:hello.world.request?level=INFO?showAll=true" />
<camel:bean ref="helloWorld" />
<camel:to uri="log:hello.world.response?level=INFO?showAll=true" />
</camel:route>
</camel:camelContext>
<bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig" />
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="jmsConnectionFactory" />
<property name="transacted" value="false" />
<property name="concurrentConsumers" value="1" />
</bean>
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="vm://localhost" />
<property name="redeliveryPolicy" ref="redeliveryPolicy" />
<property name="prefetchPolicy" ref="prefetchPolicy" />
</bean>
<bean id="prefetchPolicy" class="org.apache.activemq.ActiveMQPrefetchPolicy">
<property name="queuePrefetch" value="5" />
</bean>
<bean id="redeliveryPolicy" class="org.apache.activemq.RedeliveryPolicy">
<property name="maximumRedeliveries" value="1" />
<property name="backOffMultiplier" value="2" />
<property name="initialRedeliveryDelay" value="2000" />
<property name="useExponentialBackOff" value="true" />
</bean>
</beans>
The dateFormats and json elements are part of the camel namespace. You need to specify that
<camel:dataFormats>
<camel:json id="jack" library="Jackson"/>
</camel:dataFormats>