Difference between DefaultJMSConnectionFactory and JmsXA - jms

Out-of-the-box, Wildfly 10 configures a pooled connection factory as part of the JMS subsystem with two entries.
<pooled-connection-factory name="activemq-ra"
transaction="xa"
connectors="in-vm"
entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory"/>
One might inject a connection factory like so:
#Resource(mappedName = "java:jboss/DefaultJMSConnectionFactory")
private ConnectionFactory connectionFactory;
What is the difference between this and choosing the other entry; java:/JmsXA?

There is no difference it's an additionnal JNDI entry to suit JMS 2 spec default ConnectionFactory name : java:comp/DefaultJMSConnectionFactory
You should resolve it using this name.
Since JMS 2.0, a default JMS connection factory is accessible to EE
application under the JNDI name java:comp/DefaultJMSConnectionFactory.
WildFly messaging subsystem defines a pooled-connection-factory that
is used to provide this default connection factory. Any parameter
change on this pooled-connection-factory will be take into account by
any EE application looking the default JMS provider under the JNDI
name java:comp/DefaultJMSConnectionFactory.
See https://docs.jboss.org/author/display/WFLY9/Messaging+configuration
The other one is just a legacy identifier :
The JCA layer intercepts the calls to createConnection() and createSession() and provides a caching layer (amongst other things). So when you call createConnection() or createSession(), then, in most cases it's not really calling the actual JMS implementation to actually create a new JMS connection or JMS session, it's just returning one from it's own internal cache - in other words the JCA layer pools JMS connections and JMS sessions.
In JBoss application server, the "special" JMS connection factory which provides the JCA caching is usually available at java:/JmsXA in jndi.
See https://developer.jboss.org/wiki/ShouldICacheJMSConnectionsAndJMSSessions

Related

Spring JMS in Wildfly Appserver

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.

JNDI name format of JMS queue in wildfly10

Hi I am migrating to wildfly 10 from JBoss_6.1.0_final.
In JBoss for Queue name the format is like
<queue name="TEST_QUEUE">
<entry name="/queue/TEST_QUEUE"/>
</queue>
and in MDB annotation is
#ActivationConfigProperty(propertyName = "destination",
propertyValue = "queue/TEST_QUEUE")
Now in wildfly its like below. reference link
<jms-queue name="TEST_QUEUE" entries="jms/queue/TEST_QUEUE java:jboss/exported/jms/queue/TEST_QUEUE"/>
with activationproperty
#ActivationConfigProperty(propertyName = "destination",
propertyValue = "jms/queue/TEST_QUEUE")
In wildfly I have tried by removing the jms/ from queue name and from annotation, its working fine in wildfly with same queue name ,
like
<jms-queue name="TEST_QUEUE" entries="queue/TEST_QUEUE java:jboss/exported/queue/TEST_QUEUE"/>
Now my question is, Is JMS/ in queue name added purposefully.
it is good practice to write queue name without prefix jms/
From the JEE JSR part EE.5.7.1.2 Programming Interfaces for Resource Manager Connection Factory References
This specification recommends, but does not require, that all resource manager connection factory references be organized in the subcontexts of the application component’s environment, using a different subcontext for each resource manager type. For example, all JDBC™ DataSource references should be declared in the java:comp/env/jdbc subcontext, all JMS connection factories in the java:comp/env/jms subcontext, all JavaMail connection factories in the java:comp/env/mail subcontext, and all URL connection factories in the java:comp/env/url subcontext. Note that resource manager connection factory references declared via annotations will not, by default, appear in any subcontext
the jms subcontext is not mandatory. It is just a best practice.
Servers can or not follow this pattern. JBoss was not following this, wildfly is, but ultimately, it is YOUR decision to do what you want. But this is a really good practice to follow as it is cleaner for everybody.

Solace NIFI JMSConnectionFactoryProvider

I am trying to connect to Solace Queues on a VPN different then default using Appache NIFI ConsumeJMS Processor. When I try to enable the JMSConnectionFactoryProvider I get the following error:
JMSConnectionFactoryProvider Failed to invoke #OnEnabled method due to
java.lang.IllegalStateException: java.lang.IllegalStateException:
Failed to load and/or instantiate class
'com.solacesystems.jms.SolConnectionFactory'
The NIFI JMSConnectionFactoryProvider provides a generic service to create vendor specific javax.jms.ConnectionFactory implementations. ConnectionFactory can be served once this service is configured successfully.
Why is NIFI Unable to find the class within the Solace JMS API Jar files?
----- Update --------
Solace JMS API 10.1.0 now contains an zero argument default constructor, and integration with NiFi is now possible.
Here is an example configuration:
Controller:
The MQ ConnectionFactory Implementation is set to com.solacesystems.jms.SolConnectionFactoryImpl.
ConsumeJMS Processor:
Username field can also take the form of "myUsername#myMessageVPN".
----- Original -------
The problem here is that Apache NiFi is not using a portable method of creating a ConnectionFactory. It is trying to create a ConnectionFactory by calling an zero argument default constructor, but there's no guarantee that one exists.
// From https://github.com/apache/nifi/blob/master/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-cf-service/src/main/java/org/apache/nifi/jms/cf/JMSConnectionFactoryProvider.java
private void createConnectionFactoryInstance(ConfigurationContext context) {
String connectionFactoryImplName = context.getProperty(CONNECTION_FACTORY_IMPL).evaluateAttributeExpressions().getValue();
this.connectionFactory = Utils.newDefaultInstance(connectionFactoryImplName);
}
Note that there's an entry over at NiFi's JIRA https://issues.apache.org/jira/browse/NIFI-2701 to "Add JNDI Factory support for JMS ConnectionFactory service". (The initial description of that entry is a bit confusing, but the comments are clearer.)
At this point, Solace only supports the creation of the ConnectionFactory through the standard JNDI lookup - javax.naming.InitialContext.lookup() and through Solace's proprietary method - SolJmsUtility.createConnectionFactory().
Solace will investigate whether it is feasible to implement a zero argument default constructor for the ConnectionFactory.
A JNDI connection provider is developed and published at http://dev.solace.com/integration-guides/nifi/. For people that are interested in this provider, it is worthwhile finding out.

Spring JMS Message Redelivery not working as expected for CLIENT_ACKNOWLEDGE mode

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

how to read a jms queue from a non hosted java application?

I'm trying to read messages from a jms queue created in "Sun App Server" from a non-hosted application (console app) but I get the following error:
NoInitialContextException
Cannot instantiate class: javax.jms.TopicConnectionFactory
with this code:
Properties env = new Properties( );
env.put(Context.INITIAL_CONTEXT_FACTORY, "javax.jms.TopicConnectionFactory");
InitialContext jndi = new InitialContext(env);
and I have referenced the j2ee.jar library that contains the class but certainly, the class is an interface.
Can I access the queue from a non-hosted application??
Aitor;
When you say "Sun App Server", I'm not sure what that means, but I will assume it is Glassfish.
There are 2 separate steps to acquiring remote JMS resources.
You need to create a remote JNDI connection which requires a valid InitialContextFactory class name.
Once you have a the connection, you can look up the TopicConnectionFactory.
For item #1, this link demonstrates how to make a remote JNDI connection.
For item #2, once you have a JNDI context, you will also need to know the JNDI name of the TopicConnectionFactory which will look something like:
TopicConnectionFactory tcf = (TopicConnectionFactory) jndi.lookup("jms/TopicConnectionFactory");
One aspect you need to keep in mind is that the j2ee.jar library contains the generic Java EE interfaces for the JMS classes, but you will also need a library in your classpath that contain the JMS implementation concrete classes. This also goes for the JNDI connection. This tutorial provides a concise list as:
Applicationserver JNDI Lookup
/lib/appserv-rt.jar
/lib/appserv-admin.jar
/lib/javaee.jar /lib/j2ee.jar
Client Lib
/imq/lib/jms.jar
/imq/lib/imq.jar
/imq/lib/imqutil.jar
/lib/install/applications/jmsra/jmsra.jar

Resources