I am attempting to make an Apache Camel application that integrates with ActiveMQ over AMQP.
I have been working from the provided 'camel-example-spring-jms' project, which is over the standard TCP connection, but I have modified to use my standalone ActiveMQ 5.8 installation (rather than embedded), which I have working fine using TCP.
Active MQ Configuration (amqp on 5672)
<transportConnectors>
<transportConnector name="openwire" uri="tcp://0.0.0.0:61610?maximumConnections=1000&wireformat.maxFrameSize=104857600"/>
<transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&wireformat.maxFrameSize=104857600"/>
</transportConnectors>
Within 'camel-server.xml' I have replaced the existing "jms" 'ActiveMQComponent' with a 'JmsComponent' that references an 'AMQConnectionFactory' upon which I specify my connection URL (tried both variations below).
amqp://guest:guest#localhost/test?brokerlist='tcp://localhost:5672'
amqp://guest:guest#/?brokerlist='tcp://localhost:5672'
<bean id="jmsConnectionFactory" class="org.apache.qpid.client.AMQConnectionFactory">
<constructor-arg index="0"
value="amqp://guest:guest#localhost/test?brokerlist='tcp://localhost:5672'" />
</bean>
<bean id="jms" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsConnectionFactory" />
<property name="useMessageIDAsCorrelationID" value="true" />
</bean>
The server appears to start fine with the configuration above, but when I add a route to the amqp queue in the 'ServerRoutes.java' I get an error on startup.
from("amqp:queue:numbers").to("multiplier");
The error in the Camel Server window is:
[nsumer[numbers]] INFO AMQConnection - to broker at tcp://localhost:5672
org.apache.qpid.AMQException: Cannot connect to broker: connect() aborted [error code 200: reply success]
And the error in my ActiveMQ windows is:
org.apache.activemq.transport.amqp.AmqpProtocolException: Could not decode AMQP frame: hex: 414d51500101000a
Caused by: org.apache.qpid.proton.engine.TransportException: AMQP header mismatch value 1, expecting 0
Any help is appreicated in diagnosing this issue.
Thanks.
Right, so after lots of reading I think that ActiveMQ is AMQP 1.0 implementation and I appear to be using libraries that are using AMQP 0.10.
I was able to get this to work by adding the following mvn dependencies:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-amqp</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jms_1.1_spec</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.qpid</groupId>
<artifactId>qpid-amqp-1-0-client-jms</artifactId>
<version>0.24</version>
</dependency>
<dependency>
<groupId>org.apache.qpid</groupId>
<artifactId>qpid-amqp-1-0-client</artifactId>
<version>0.24</version>
</dependency>
And using this connection factory:
<bean id="jmsConnectionFactory" class="org.apache.qpid.amqp_1_0.jms.impl.ConnectionFactoryImpl" factory-method="createFromURL">
<constructor-arg index="0" type="java.lang.String" value="amqp:///?brokerlist='tcp://localhost:5672''" />
Related
Whenever I try to stop ActiveMQ installed on RHEL server, it doesn't stops gracefully. Does anyone knows why? I am not sure why it tries to connect to JMX broker as shown below and fails. What do I need to fix these issues?
[activemq#myserver apache-activemq-5.15.11]$ bin/activemq stop
INFO: Loading '/web/servers/apache-activemq-5.15.11//bin/env'
INFO: Using java '/bin/java'
INFO: Waiting at least 30 seconds for regular process termination of pid '2963' :
Java Runtime: Oracle Corporation 1.8.0_252 /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.252.b09-2.el7_8.x86_64/jre
Heap sizes: current=62976k free=61991k max=932352k
JVM args: -Xms64M -Xmx1G -Djava.util.logging.config.file=logging.properties -Djava.security.auth.login.config=/web/servers/apache-activemq-5.15.11//conf/login.config -Dactivemq.classpath=/web/servers/apache-activemq-5.15.11//conf:/web/servers/apache-activemq-5.15.11//../lib/: -Dactivemq.home=/web/servers/apache-activemq-5.15.11/ -Dactivemq.base=/web/servers/apache-activemq-5.15.11/ -Dactivemq.conf=/web/servers/apache-activemq-5.15.11//conf -Dactivemq.data=/web/servers/apache-activemq-5.15.11//data
Extensions classpath:
[/web/servers/apache-activemq-5.15.11/lib,/web/servers/apache-activemq-5.15.11/lib/camel,/web/servers/apache-activemq-5.15.11/lib/optional,/web/servers/apache-activemq-5.15.11/lib/web,/web/servers/apache-activemq-5.15.11/lib/extra]
ACTIVEMQ_HOME: /web/servers/apache-activemq-5.15.11
ACTIVEMQ_BASE: /web/servers/apache-activemq-5.15.11
ACTIVEMQ_CONF: /web/servers/apache-activemq-5.15.11/conf
ACTIVEMQ_DATA: /web/servers/apache-activemq-5.15.11/data
Connecting to pid: 2963
INFO: failed to resolve jmxUrl for pid:2963, using default JMX url
Connecting to JMX URL: service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
INFO: Broker not available at: service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
...............................
INFO: Regular shutdown not successful, sending SIGKILL to process
INFO: sending SIGKILL to pid '2963'
EDIT:
Adding activemq.xml configuration file
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<!-- START SNIPPET: example -->
<beans
xmlns="http://www.springframework.org/schema/beans"
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://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
<!-- Allows us to use system properties as variables in this configuration file -->
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<value>file:${activemq.conf}/credentials.properties</value>
</property>
</bean>
<!-- Allows accessing the server log -->
<bean id="logQuery" class="io.fabric8.insight.log.log4j.Log4jLogQuery"
lazy-init="false" scope="singleton"
init-method="start" destroy-method="stop">
</bean>
<!--
The <broker> element is used to configure the ActiveMQ broker.
-->
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">
<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>
<!--
The managementContext is used to configure how ActiveMQ is exposed in
JMX. By default, ActiveMQ uses the MBean server that is started by
the JVM. For more information, see:
http://activemq.apache.org/jmx.html
-->
<managementContext>
<managementContext createConnector="false"/>
</managementContext>
<!--
Configure message persistence for the broker. The default persistence
mechanism is the KahaDB store (identified by the kahaDB tag).
For more information, see:
http://activemq.apache.org/persistence.html
-->
<persistenceAdapter>
<kahaDB directory="${activemq.data}/kahadb"/>
</persistenceAdapter>
<!--
The systemUsage controls the maximum amount of space the broker will
use before disabling caching and/or slowing down producers. For more information, see:
http://activemq.apache.org/producer-flow-control.html
-->
<systemUsage>
<systemUsage>
<memoryUsage>
<memoryUsage percentOfJvmHeap="70" />
</memoryUsage>
<storeUsage>
<storeUsage limit="100 gb"/>
</storeUsage>
<tempUsage>
<tempUsage limit="50 gb"/>
</tempUsage>
</systemUsage>
</systemUsage>
<!--
The transport connectors expose ActiveMQ over a given protocol to
clients and other brokers. For more information, see:
http://activemq.apache.org/configuring-transports.html
-->
<transportConnectors>
<!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
<transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
<transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&wireFormat.maxFrameSize=104857600"/>
</transportConnectors>
<!-- destroy the spring context on shutdown to stop jetty -->
<shutdownHooks>
<bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
</shutdownHooks>
</broker>
<!--
Enable web consoles, REST and Ajax APIs and demos
The web consoles requires by default login, you can disable this in the jetty.xml file
Take a look at ${ACTIVEMQ_HOME}/conf/jetty.xml for more details
-->
<import resource="jetty.xml"/>
</beans>
<!-- END SNIPPET: example -->
Adding activemq.log file from /web/servers/apache-activemq-5.15.11/data
Pasting shareable link below:
https://drive.google.com/file/d/1vQ6HkOu53mzMi-GqbGxaQP6EJNC4RT4G/view?usp=sharing
Don't know if this is the issue for you, but after some reading it sounded like activemq uses jmx for its shutdown hook, but the default config that ships with activemq does not setup the jmx connector.
For me, activemq was able to shutdown if I changed:
<managementContext>
<managementContext createConnector="false"/>
</managementContext>
To specify a jmx connectorPort:
<managementContext>
<managementContext connectorPort="1099"/>
</managementContext>
Some references:
Activemq Shutdown fails and then kills process
https://issues.apache.org/jira/browse/AMQ-6927
Below are components used
Load balancer - spring boot zuul ribbon
Server - tomcat7
Web application - spring version 4.1
Cache mode - partitioned
No. of nodes - 2
Web clustering configuration
https://apacheignite-mix.readme.io/docs/web-session-clustering
I have a web application which uses sticky session and I want to migrate to a non-sticky session using apache ignite. I followed the apache ignite "web session clustering" guide to implement the change. Added a load balancer which routes the traffic in a round-robin mechanism to the configured list of nodes. I run node 1 on port 8080 and node 2 on port 9090. Both nodes are configured in ribbon load balancer.
After the configuration change as mentioned in the guide, I was able to run single node successfully. I was able to see the sessions and values in apache ignite cache using below command in visor
./ignitevisorcmd.sh
cache session-cache -scan
But when I start the second node and requests hits node 2 the session becomes invalid and application throws error due to unavailability of session information.
My suspicion is that node 2 of tomcat creates a new session before "apache-ignite" WebSessionFilter.class is invoked and tomcat is not aware a session already exists in ignite. Then when org.apache.ignite.cache.websession.WebSessionFilter is invoked it wraps the newly created HttpSession with org.apache.ignite.cache.websession.WebSessionV2 and pushes to the cache store as a new session. FYI, I do initialize the session with few objects using a SessionListener.
Following are the checks/trials I did before posting here
My configuration exactly matches with the documentation.
WebSessionFilter is first in the filter order
Confirmed that both nodes are attached, using status command
Tried cache-mode as "replicated"
Tried on tomcat8 and found same issue.
default-config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!--
Alter configuration below as needed.
-->
<bean id="grid.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
<property name="cacheConfiguration">
<bean id="igniteCacheConfiguration" class="org.apache.ignite.configuration.CacheConfiguration">
<!-- Cache name. -->
<property name="name" value="session-cache"/>
<!-- Cache mode. -->
<property name="cacheMode" value="PARTITIONED"/>
<property name="backups" value="2"/>
<property name="statisticsEnabled" value="true"/>
<property name="managementEnabled" value="true" />
</bean>
</property>
</bean>
web.xml
<listener>
<listener-class>org.apache.ignite.startup.servlet.ServletContextListenerStartup</listener- class>
</listener>
<filter>
<filter-name>IgniteWebSessionsFilter</filter-name>
<filter-class>org.apache.ignite.cache.websession.WebSessionFilter</filter-class>
</filter>
<!-- You can also specify a custom URL pattern. -->
<filter-mapping>
<filter-name>IgniteWebSessionsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Specify Ignite configuration (relative to META-INF folder or Ignite_HOME). -->
<context-param>
<param-name>IgniteConfigurationFilePath</param-name>
<param-value>default-config.xml </param-value>
</context-param>
<!-- Specify the name of Ignite cache for web sessions. -->
<context-param>
<param-name>IgniteWebSessionsCacheName</param-name>
<param-value>session-cache</param-value>
</context-param>
pom.xml
<ignite.version>2.6.0</ignite.version>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-core</artifactId>
<version> ${ignite.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-web</artifactId>
<version> ${ignite.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-log4j</artifactId>
<version>${ignite.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.apache.ignite</groupId>
<artifactId>ignite-spring</artifactId>
<version>${ignite.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
<version>1.1.0</version>
</dependency>
I need to understand what needs to be done to make web session work with 2 nodes.
Figured out that the root cause for the issue was that we were using SessionRequestListeners which were accessing session information. These Listeners are invoked before Apache Ignite WebFilter resulting in creation of a new session before Ignite could find the session in the Ignite's cache. As a new session is available when Apache Ignite WebFilter is invoked it just uses the existing session and caches it.
Solution - Used Filters in place of critical Listeners and removed non-critical Listeners and its working now.
e.g.
Removed org.springframework.web.context.request.RequestContextListener
Added org.springframework.web.filter.RequestContextFilter after IgniteFilter in order
I'm getting the following exception when I re-deploy the application war in the Tomcat manager. For example, on first time deployment it connects to the external ActiveMQ properly but when I stop/start the war in Tomcat manager, then the following execption is thrown repeatedly. After this, the JMS does not connect to ActiveMQ with the below exception:
[2015-09-13T04:03:33.689] | [ERROR] | [inventorydsRequestListenerContainer-1] | [Could not refresh JMS Connection for destination 'queue://inventorydsDestination' - retrying in 5000 ms. Cause: AOP configuration seems to be invalid: tried calling method [public abstract javax.jms.Connection javax.jms.ConnectionFactory.createConnection() throws javax.jms.JMSException] on target [org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter#168d95c7]; nested exception is java.lang.IllegalArgumentException: java.lang.ClassCastException#2fb6f3c3]
applicationContext-Jms.xml
<bean id="jmsJndiConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${inventory.mq.name}"/>
<property name="lookupOnStartup" value="false"/>
<property name="cache" value="true" />
<property name="proxyInterface" value="javax.jms.QueueConnectionFactory" />
</bean>
<bean id="jmsConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsJndiConnectionFactory" />
<property name="sessionCacheSize" value="10" />
</bean>
connectionFactory - JNDI configuration
<bean id="jndiName" class="java.lang.String">
<constructor-arg value="${inventory.mq.name}"/>
</bean>
<bean id="bindingObject" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="mqConnectionFactory" />
<property name="username" value="${inventory.activeMQ.username}" />
<property name="password" value="${inventory.activeMQ.password}" />
</bean>
<bean id="mqConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${inventory.activeMQ.brokerurl}" />
</bean>
Properties:
inventory.activeMQ.brokerurl=tcp://localhost:61616
inventory.activeMQ.username=admin
inventory.activeMQ.password=admin
inventory.mq.name=jms/connectionFactory
inventory.queue.type=org.apache.activemq.command.ActiveMQQueue
I had similar issue and discovered it was a classpath issue between tomcat and my web application. I needed to set the scope of the jms dependency in my web app to provided instead of the default (i.e. compile). That way, my WAR deployable did not contain another jms jar that clashed with the jms classes contained in the apache-activemq-all jar that was located in the tomcat lib folder.
<dependency>
<groupId>javax.jms</groupId>
<artifactId>jms-api</artifactId>
<version>1.1-rev-1</version>
<scope>provided</scope>
</dependency>
Try after skipping ALL Breakpoints in Debug mode/ Switch off Debug Mode or Run in Run Mode
SpringJMS 3.0.4 not connecting MQ 7.5 Connection using UserName
Not able to connect MQ 7.5 Queue manager from Spring JMS version 3.0.4 with username. Username is passed to provide appropriate authorization to queue. We are using SpringJMS which uses MQ Client libraries available on the same machine. MQ Manager/Server is on remote machine
Below is the configuration we are using but we are getting error message as shown below
<?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:jms="http://www.springframework.org/schema/jms" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd">
<!-- :: Messaging Infrastructure Beans :: -->
<bean id="transport" class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean" p:staticField="com.ibm.mq.jms.JMSC.MQJMS_TP_CLIENT_MQ_TCPIP" />
<bean id="mqConnectionFactory" class="com.ibm.mq.jms.MQQueueConnectionFactory" p:transportType-ref="transport"
p:queueManager="${tcs.messaging.queueManager.name}" p:hostName="${tcs.messaging.queueManager.host}" p:port="${tcs.messaging.queueManager.port}"
p:channel="${tcs.messaging.queueManager.channel}" />
<bean id="queueConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory"
p:targetConnectionFactory-ref="mqConnectionFactory" p:sessionCacheSize="${tcs.messaging.connectionFactory.sessionCacheSize}"
p:exceptionListener-ref="providerMessageListener" />
<bean id="providerMessageListener" class="com.uhg.treasury.customerservice.management.transport.jms.ProviderExceptionListener" />
<!-- New Addition :: -->
<bean id="myConnectionFactory2" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory"> <ref bean ="mqConnectionFactory"/> </property>
<property name="username"> <value>"tbossmqd"</value> </property>
<property name="password"> <value>"password1"</value> </property>
</bean>
</beans>
Error Message is as below
2014-06-27 11:25:42,503 [main] DEBUG - DefaultMessageListenerContainer.establishSharedConnection(752) | Could not establish shared JMS Connection - leaving it up to asynchronous invokers to establish a Connection as soon as possible
com.ibm.msg.client.jms.DetailedJMSSecurityException: JMSWMQ2013: The security authentication was not valid that was supplied for QueueManager 'WMQT013' with connection mode 'Client' and host name 'wmqlt0006.xxx.com(1960)'.
Please check if the supplied username and password are correct on the QueueManager to which you are connecting.
at com.ibm.msg.client.wmq.common.internal.Reason.reasonToException(Reason.java:521)
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:221)
at com.ibm.msg.client.wmq.internal.WMQConnection.(WMQConnection.java:426)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createV7ProviderConnection(WMQConnectionFactory.java:6902)
at com.ibm.msg.client.wmq.factories.WMQConnectionFactory.createProviderConnection(WMQConnectionFactory.java:6277)
at com.ibm.msg.client.jms.admin.JmsConnectionFactoryImpl.createConnection(JmsConnectionFactoryImpl.java:285)
at com.ibm.mq.jms.MQConnectionFactory.createCommonConnection(MQConnectionFactory.java:6233)
at com.ibm.mq.jms.MQQueueConnectionFactory.createQueueConnection(MQQueueConnectionFactory.java:120)
at com.ibm.mq.jms.MQQueueConnectionFactory.createConnection(MQQueueConnectionFactory.java:203)
at org.springframework.jms.connection.SingleConnectionFactory.doCreateConnection(SingleConnectionFactory.java:342)
at org.springframework.jms.connection.SingleConnectionFactory.initConnection(SingleConnectionFactory.java:288)
at org.springframework.jms.connection.SingleConnectionFactory.createConnection(SingleConnectionFactory.java:225)
at org.springframework.jms.support.JmsAccessor.createConnection(JmsAccessor.java:184)
at org.springframework.jms.listener.AbstractJmsListeningContainer.createSharedConnection(AbstractJmsListeningContainer.java:403)
at org.springframework.jms.listener.AbstractJmsListeningContainer.establishSharedConnection(AbstractJmsListeningContainer.java:371)
at org.springframework.jms.listener.DefaultMessageListenerContainer.establishSharedConnection(DefaultMessageListenerContainer.java:749)
at org.springframework.jms.listener.AbstractJmsListeningContainer.doStart(AbstractJmsListeningContainer.java:278)
at org.springframework.jms.listener.AbstractJmsListeningContainer.start(AbstractJmsListeningContainer.java:263)
at org.springframework.jms.listener.DefaultMessageListenerContainer.start(DefaultMessageListenerContainer.java:555)
at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:166)
at org.springframework.context.support.DefaultLifecycleProcessor.access$1(DefaultLifecycleProcessor.java:154)
at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:335)
at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:143)
at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:108)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:908)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:428)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:197)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:172)
at org.springframework.context.support.ClassPathXmlApplicationContext.(ClassPathXmlApplicationContext.java:158)
at com.uhg.treasury.customerservice.management.Server.(Server.java:61)
at com.uhg.treasury.customerservice.management.Server.(Server.java:43)
Caused by: com.ibm.mq.MQException: JMSCMQ0001: WebSphere MQ call failed with compcode '2' ('MQCC_FAILED') reason '2035' ('MQRC_NOT_AUTHORIZED').
at com.ibm.msg.client.wmq.common.internal.Reason.createException(Reason.java:209)
... 29 more
2014-06-27 11:25:42,512 [main] DEBUG - AbstractJmsListeningContainer.resumePausedTasks(539) | Resumed paused task: org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker#627a94a9
2014-06-27 11:25:42,512 [main] DEBUG - AbstractJmsListeningContainer.resumePausedTasks(539) | Resumed paused task: org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker#5db615c1
I can confirm that the MQQueueuConnectionFactory.createConnection method been called by Spring is the version that passes no username/password. This is why you are seeing the MQRC_NOT_AUTHORIZED as the username is not being passed to the queue manager.
I am not a spring expert but I believe that the new myConnectionFactory2 bean that you have added needs to reference your CachingConnectionFactory bean (queueConnectionFactory) rather than directly referencing the MQQueueConnectionFactory bean (mqConnectionFactory). So change this:
<bean id="myConnectionFactory2" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory"> <ref bean ="mqConnectionFactory"/> </property>
<property name="username"> <value>"tbossmqd"</value> </property>
<property name="password"> <value>"password1"</value> </property>
</bean>
to be this:
<bean id="myConnectionFactory2" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory"> <ref bean ="queueConnectionFactory"/> </property>
<property name="username"> <value>"tbossmqd"</value> </property>
<property name="password"> <value>"password1"</value> </property>
</bean>
Hello has anyone ever used Camel with IBM's MQ. We are looking at possibly using the two products together but have no example of the two products working together.
I have extensive use of IBM MQ's with camel. There is no issue using both together. I will paste a sample configuration from one of my spring context files leveraging a camel Jms Endpoint, A spring connection factory, and an IBM MQ definition.
Camel Route
from("someplace")
.to("cpaibmmq:queue:myQueueName");
Spring Context
<bean name="cpaibmmq" class="org.apache.camel.component.jms.JmsComponent" destroy-method="doStop">
<property name="transacted" value="${jms.transacted}" />
<property name="concurrentConsumers" value="${cpa.concurrentConsumers}" />
<property name="maxConcurrentConsumers" value="${cpa.concurrentConsumers}" />
<property name="acceptMessagesWhileStopping" value="${jms.acceptMessagesWhileStopping}" />
<property name="acknowledgementModeName" value="${jms.acknowledgementModeName}" />
<property name="cacheLevelName" value="${jms.cacheLevelName}" />
<property name="connectionFactory" ref="ibmFac1" />
<property name="exceptionListener" ref="ibmFac1" />
</bean>
<bean id="ibmFac1" class="org.springframework.jms.connection.SingleConnectionFactory" destroy-method="destroy">
<constructor-arg>
<bean class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="transportType" value="1" />
<property name="channel" value="${cpa.wmq.channel}" />
<property name="hostName" value="${cpa.wmq.hostname}" />
<property name="port" value="${cpa.wmq.port}" />
<property name="queueManager" value="${cpa.wmq.mqmanager}" />
</bean>
</constructor-arg>
</bean>
The best I have been able to get is documented below, illustrated as a Spring XML application context that itself hosts the CAMEL context and routes. This sample works with the IBM native MQ JCA-compliant resource adapter v7.5, CAMEL 2.16, Spring core 4.2. I have deployed it in Glassfish, Weblogic, and JBoss EAP7 servers.
The complexity is bound to handling the flow of MQ reports whose philosophy conflicts with that of a plain JMS reply-to message. For a detailed explanation, please refer to Implementing native websphere MQ with CoD over Camel JMS component
This example based on the CAMEL XML DSL is self-contained and easy to test.
We start with Spring & CAMEL declarations:
<?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:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:jee="http://www.springframework.org/schema/jee"
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.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
The CAMEL context follows with 2 routes: MQ to JMS and JMS to MQ, here chained to form a bridge to ease testing.
<camel:camelContext id="mqBridgeCtxt">
<camel:route id="mq2jms" autoStartup="true">
Weird: on Weblogic, the only way to get (e.g.) 3 listeners is to enforce 3 connections (with 3 Camel:from statements in sequence) with max 1 session each, otherwise an MQ error ensues: MQJCA1018: Only one session per connection is allowed. On JBoss, you can simply adjust concurrentConsumers=...
<camel:from uri="wmq:queue:TEST.Q1?concurrentConsumers=1&disableReplyTo=true&
acknowledgementModeName=SESSION_TRANSACTED"/>
The disable disableReplyTo option above ensures that CAMEL will not produce a reply before we can test the MQ message type to be 1=Request(-reply) or 8=datagram (one way!). That test and reply construction is not illustrated here.
Then we enforce the EIP to InOnly on the next posting to plain JMS to be consistent with the Inbound MQ mode.
<camel:setExchangePattern pattern="InOnly"/>
<!-- camel:process ref="reference to your MQ message processing bean fits here" / -->
<camel:to uri="ref:innerQueue" />
</camel:route>
This ends the MQ-to-jms route; next comes the jms-to-MQ route still in the same CAMEL context:
<camel:route id="jms2mq" autoStartup="true">
<camel:from uri="ref:innerQueue" />
<!-- remove inner message headers and properties to test without inbound side effects! -->
<camel:removeHeaders pattern="*"/>
<camel:removeProperties pattern="*" />
<!-- camel:process ref="reference to your MQ message preparation bean fits here" / -->
Now comes the request flag for the MQ CoD report to be returned by remote destination. We also enforce the MQ message to be of Datagram type (value 8).
<camel:setHeader headerName="JMS_IBM_Report_COD"><camel:simple resultType="java.lang.Integer">2048</camel:simple></camel:setHeader>
<camel:setHeader headerName="JMS_IBM_Report_Pass_Correl_ID"><camel:simple resultType="java.lang.Integer">64</camel:simple></camel:setHeader>
<camel:setHeader headerName="JMS_IBM_MsgType"><camel:simple resultType="java.lang.Integer">8</camel:simple></camel:setHeader>
The ReplyTo queue can be specified either via the ReplyTo uri option, else as a header as below.
Next we do use CamelJmsDestinationName header to enforce suppressing of the JMS MQ message header MQRFH2 (using targetClient MQ URL option value 1). In other words, we want to send a plain vanilla MQ binary message (i.e. Only the MQMD message descriptor followed by the payload).
<camel:setHeader headerName="JMSReplyTo"><camel:constant>TEST.REPLYTOQ</camel:constant></camel:setHeader>
<camel:setHeader headerName="CamelJmsDestinationName"> <camel:constant>queue://MYQMGR/TEST.Q2?targetClient=1</camel:constant></camel:setHeader>
More MQMD fields may be controlled through reserved JMS properties as illustrated below. See restrictions in IBM doc.
<camel:setHeader headerName="JMS_IBM_Format"><camel:constant>MQSTR </camel:constant></camel:setHeader>
<camel:setHeader headerName="JMSCorrelationID"><camel:constant>_PLACEHOLDER_24_CHARS_ID_</camel:constant></camel:setHeader>
The destination queue in the URI is overwritten by the CamelJmsDestinationName above, hence the queue name in the URI becomes a placeholder.
The URI option preserveMessageQos is the one that - as observed - allows sending a message with the ReplyTo data being set (to get the MQ CoD Report), yet prevent CAMEL to instantiate a Reply message listener by enforcing the InOnly MEP.
<camel:to uri="wmq:queue:PLACEHOLDER.Q.NAME?concurrentConsumers=1&
exchangePattern=InOnly&preserveMessageQos=true&
includeSentJMSMessageID=true" />
</camel:route>
</camel:camelContext>
We have not finished, we have still to declare our queue factories for both a native JMS provider and Websphere MQ (via the native IBM WMQ JCA Resource Adapter), to be adjusted to your context.
We use here JNDI lookups on administrative objects.
<camel:endpoint id="innerQueue" uri="jmsloc:queue:transitQueue">
</camel:endpoint>
<jee:jndi-lookup id="mqQCFBean" jndi-name="jms/MYQMGR_QCF"/>
<jee:jndi-lookup id="jmsraQCFBean" jndi-name="jms/jmsra_QCF"/>
<bean id="jmsloc" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="jmsraQCFBean" />
</bean>
<bean id="wmq" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="mqQCFBean" />
</bean>
</beans>
An alternative to fetching the factories (and JCA adapters) from JNDI is to declare the JMS client as Spring beans. In Weblogic and Glassfish, you'll be better inspired by deploying the native IBM JCA resource adapter and creating JNDI resources then referenced in the Spring Context as above, in JBoss a direct MQ client bean declaration suits best as below)
<bean id="mqCFBean" class="com.ibm.mq.jms.MQXAConnectionFactory">
<property name="hostName" value="${mqHost}"/>
<property name="port" value="${mqPort}"/>
<property name="queueManager" value="${mqQueueManager}"/>
<property name="channel" value="${mqChannel}"/>
<property name="transportType" value="1"/> <!-- This parameter is fixed and compulsory to work with pure MQI java libraries -->
<property name="appName" value="${connectionName}"/>
</bean>
<bean id="wmq" class="org.apache.camel.component.jms.JmsComponent">
<property name="connectionFactory" ref="mqCFBean"/>
<property name="transacted" value="true"/>
<property name="acknowledgementModeName" value="AUTO_ACKNOWLEDGE"/>
</bean>
Comments and improvements welcome.
A quick google revealed following,
http://lowry-techie.blogspot.de/2010/11/camel-integration-with-websphere-mq.html
HTH