I need to connect from code running in WebSphere Liberty to an MDB in Apache TomEE Plume. I am using activemq-rar-5.16.3.
Here is the Java code:
public void notifyListeners(String caseId) {
logger.debug("+notifyListeners");
int timeToLive = 15 * 1000; // 15 seconds
try {
logger.debug("Creating context");
InitialContext ic = new InitialContext();
logger.debug("Got Initial context");
ConnectionFactory jmsFactory = (ConnectionFactory)ic.lookup("jndi/JMS_BASE_QCF");
logger.debug("Got Factory");
JMSContext context = jmsFactory.createContext();
logger.debug("Creating text message");
TextMessage msg = context.createTextMessage(caseId);
logger.debug("Sending text message");
context.createProducer().setTimeToLive(timeToLive).send(jmsSendQueue, msg);
logger.debug("Text message sent");
} catch (Throwable e) {
logger.error("Caught Exception sending ActiveMQ Message : " + e, e);
}
logger.debug("-notifyListeners");
}
No matter what I try, the code hangs at jmsFactory.createContext(). There's no exception. It just hangs.
I can see from the Apache TomEE logs that an ActiveMQ listener has been created on tcp://127.0.0.1:61616 and verified this with a netstat command.
I can't move to the later version of the rar because it relies upon a Java 11 JRE.
Does anyone have any ideas how I can debug this? Wireshark shows nothing, and changing the Liberty definition to point the ActiveMQ Connection Factory to 61615 changes nothing - so I don't think the createContext method is getting as far as contacting the ActiveMQ broker. It's hardly relevant, but this method runs in an asynchronous CDI event handler in Liberty. There is nothing untoward in the Liberty logs, and no FFDC events.
Some more details:
Liberty: product = WebSphere Application Server 21.0.0.1 (wlp-1.0.48.cl210120210113-1459)
Apache TomEE: Apache Tomcat (TomEE)/9.0.52 (8.0.8)
My server.xml (relevent bits):
<!-- language: xml -->
<featureManager>
<feature>ejbLite-3.2</feature>
<feature>jaxws-2.2</feature>
<feature>jndi-1.0</feature>
<feature>jpa-2.2</feature>
<feature>jpaContainer-2.2</feature>
<feature>jsp-2.3</feature>
<feature>localConnector-1.0</feature>
<feature>mdb-3.2</feature>
<feature>microProfile-3.3</feature>
<feature>monitor-1.0</feature>
<feature>wasJmsClient-2.0</feature>
<feature>wasJmsSecurity-1.0</feature>
<feature>wasJmsServer-1.0</feature>
<feature>wmqJmsClient-2.0</feature>
<feature>jms-2.0</feature>
</featureManager>
<!--============================================= -->
<!-- Liberty to TomEE JMS over ActiveMQ Config -->
<!--============================================= -->
<resourceAdapter id="activemq" location="C:\apps\liberty\ActiveMQRAR\activemq-rar-5.16.3.rar">
<properties.activemq ServerUrl="tcp://127.0.0.1:61616"/>
</resourceAdapter>
<jmsQueueConnectionFactory jndiName="jndi/JMS_BASE_QCF">
<properties.activemq serverUrl="tcp://127.0.0.1:61616"/>
</jmsQueueConnectionFactory>
<jmsQueue jndiName="jndi/worklistQueue">
<properties.activemq PhysicalName="jms/worklistQueue"/>
</jmsQueue>
<!--============================================= -->
<!-- Liberty to TomEE JMS over ActiveMQ Config end-->
<!--============================================= -->
My main concern here is the use of createContext() in your notifyListeners method. ActiveMQ "Classic" (i.e. 5.x) doesn't fully support JMS 2 so you can't use the JMSContext API with it. JMS 2 is backwards compatible with JMS 1.1 (which ActiveMQ "Classic" fully supports) so you can still integrate using the ActiveMQ "Classic" JCA RA. You just can't use any APIs which are specific to JMS 2 (e.g. createContext()).
Related
I'm using a Spring-Boot-WAR deployed in Wildfly 14 and have implemented a JmsListener which is connected to a Queue. The JmsListener has set the concurrency to 5 and when the Spring-App is starting standalone I see 5 parallel working listeners. But in combination with Wildfly 14, there is only 1 listener running.
In JEE I would annotate the MessageDrivenBean with #Pool and then can configure the max-pool-size for the given pool. But I think the Spring-Listener just connects to the default MDB-Pool which has a size of 1.
Is there a way to connect the JmsListener with a specific bean-instance-pool? Or is there any other way to define an individual max-pool-size for this JmsListener?
standalone.xml
<subsystem xmlns="urn:jboss:domain:ejb3:5.0">
...
<pools>
<bean-instance-pools>
...
<strict-max-pool name="individual-strict-max-pool" max-pool-size="5" instance-acquisition-timeout="5" instance-acquisition-timeout-unit="MINUTES"/>
</bean-instance-pools>
</pools>
JmsListener
#JmsListener(destination = JMS_MESSAGE_NAME, concurrency = "5")
public void receiveFromMessageQueue(Message msg) {
...
}
In a JEE application server, the JCA specification limits the number of JMS sessions on a JMS connection to one. In your Spring Boot deployment, you have the 5 concurrent consumers on the JmsListener. This is achieved by having 5 JMS sessions on the one JMS connection that is managed by the Spring JMS Listener Container.
If you instantiate your own connection factory (not using the Wildfly JCA connection factories), then you can have multiple sessions per connection.
We develop a microservice based on Apache Camel JMS component and Spring Boot. IBM MQ is used as messaging middleware. There is an issue with exception listener - IBM MQ classes can't find registered exception listener and print it's own stack trace in system out when connection with MQ is broken:
com.ibm.msg.client.jms.internal.JmsProviderExceptionListener
The exception is ignored as no exception listener is registered: '
Message : com.ibm.msg.client.jms.DetailedJMSException: JMSWMQ1107: A problem with this connection has occurred.
An error has occurred with the IBM MQ JMS connection.
Use the linked exception to determine the cause of this error.
org.springframework.jms.connection.CachingConnectionFactory is used for connection setup.
#Bean
protected final ConnectionFactory createMqJmsConnectionFactory() {
MQQueueConnectionFactory mqFactory = new MQQueueConnectionFactory();
// Factory setup
CachingConnectionFactory cachingFactory = new CachingConnectionFactory(mqFactory);
return cachingFactory;
}
CachingConnectionFactory's ancestor implementes javax.jms.ExceptionListener and, as I found on Spring forum, registers itself as exceptionListener. From stack trace I can see that onException() method is invoked after exception, resets connection and writes log.
So we have a situation when IBM MQ ignores CachingConnectionFactory as exception listener. Camel JMS component has exceptionListener endpoint configuration option - I assume, adding of the CachingConnectionFactory here would be redundantly.
Any other settings need to be done in order to register CachingConnectionFactory as exception listener?
My environment: spring 4.1, JBoss EAP 6.4, IBM MQ 8.0:
Messages are not redelivered in the case where Listener throws RuntimeException.
I have the following in JmsConfig:
#Bean
DefaultMessageListenerContainer defaultMessageListenerContainer(QueueConnectionFactory connectionFactory, JndiDestinationResolver dr, MessageListener ml) {
DefaultMessageListenerContainer mlc = new DefaultMessageListenerContainer();
mlc.setConnectionFactory(connectionFactory);
mlc.setMessageListener(ml);
mlc.setDestinationName(jndiInQueue);
mlc.setDestinationResolver(dr);
mlc.setSessionTransacted(true);
mlc.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
return mlc;
}
If I use a JmsTransactionManager and pass it to the above method and use like so:
mlc.setTransactionManager(tm)
Following warnings are written to the log:
It is not valid to commit a non-transacted session, and the behavior is the same, no redelivery.
ConnectionFactory is obtained via JNDI, I wonder if sourcing the ConnectionFactory through jndi has something to do with this?
From the AbstractMessageListenerContainer Javadocs:
In order to consistently arrange for redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or - preferably - setting "sessionTransacted" to "true" instead
There is a similar question on SO.
Flip your ack mode to Session.SESSION_TRANSACTED instead of CLIENT_ACKNOWLEDGE.
Client Ack mode doesn't work as most folks want it.. and is a common "gotcha" in JMS. It acknowledges current message AND all previous messages in the session. It is not per-message acknowledgement.
Edit:
Also check related post-- IBM MQ may require you to use the "XA" versions of the connection factory class.
ref: Websphere Liberty profile - transacted Websphere MQ connection factory
I am getting the below error while invoking a JMS adapter(connects to Websphere MQ Server)
"JMS connection exception received: null. Closing the connection"
Please see below configurations (initialContextFactory, connectionFactory and destination)
MQJMSAdapter.xml
<connectivity>
<connectionPolicy xsi:type="jms:JMSConnectionPolicyType">
<!-- uncomment this if you want to use an external JNDI repository -->
<namingConnection url="file:/C:/JNDI-DIRECTORY/"
initialContextFactory="com.sun.jndi.fscontext.RefFSContextFactory"
/>
<jmsConnection
connectionFactory="myCF"
/>
</connectionPolicy>
<loadConstraints maxConcurrentConnectionsPerNode="10"/>
</connectivity>
I have installed and configured IBM Websphere MQ server in my local machine and followed below guide to configure the JNDI namesapce and administered objects
http://pic.dhe.ibm.com/infocenter/prodconn/v1r0m0/index.jsp?topic=%2Fcom.ibm.scenarios.wmqwasmig2v7.doc%2Ftopics%2Fins_sample.htm
Kindly give your inputs. Thanks in Advance
I have a Spring JMS application. Infact there is no UI. Just Spring configuration (JMS listener) and the Spring configuration is loaded by web.xml .
so when i deploy in server, the listener starts working.
But I do not want the web part, because, there no UI, It is just a project which listen to a Queue and do its processing. So I think it should be JAR and it should run standalone(or when i deploy in server) How to create such project/ JAR when deployed in server it automatically starts running. I do not want run a main class every time I update the JAR.
I have used an executable jar to launch a JMS queue before. You just have to make sure you have access to all the jar dependencies for Spring and JMS, which is a lot. This can be done by setting the classpath to point at the dependency jars or create an Uberjar and pack all the dependency jars in the executable jar.
Here is an example class that will start up ActiveMQ from a Jar when you set it as a the main-class in the jar manifest. A jms.pid will be created with the process id for process. You must set the paths to your Spring contexts for JMS in the ConfigurableApplicationContext.
public class Server {
public static void main(String[] args) throws Exception {
// Define Spring contexts required for JMS to run
List<String> contexts = Arrays.asList( "classpath:applicationContext.xml", "classpath:spring/jmsContext.xml" );
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext(contexts);
// Get activeMQ from JMS context
BrokerService broker = applicationContext.getBean( "broker" );
// Start up activeMQ
broker.start();
// Get pid for this process
String sysId = ManagementFactory.getRuntimeMXBean().getName();
String pid = sysId.substring(0, sysId.indexOf("#"));
// Write PID file
File file = new File("jms.pid");
DataOutputStream outs = new DataOutputStream(new FileOutputStream(file, false));
outs.write(pid.getBytes());
outs.close();
}
}
Example Spring configuration for getting access to the BrokerService
<bean id="broker" class="org.apache.activemq.xbean.BrokerFactoryBean">
<property name="config" value="classpath:org/activemq/xbean/activemq.xml" />
<property name="start" value="true" />
</bean>
I have typically seen JMS applications run as Windows Services or Unix daemons. These provide you features that you can configure like restarting your JMS app if the server reboots, etc.
There are some commercial Java EE containers like Weblogic that provide start-up classes that you can use to start your JMS application when a node in the cluster starts. This provides console control over the JMS application / server. It doesn't sound like that is an option in your case though.