Solace NIFI JMSConnectionFactoryProvider - apache-nifi

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.

Related

DefaultJmsListenerContainer using BeanFactoryPostProcessor

I am currently trying to support dynamic multiple jms provider scenario in my application. So far I did achieved to create DefaultMessageListenerContainer using post processor. Cool part is that the DefaultMessageContainerListener has destinationName property where you can easily set the queue to be listened/sent for messages.
However, the DefaultJmsListenerContainerFactory has no such method to set the queue name. I do reached at around the SimpleJmsListenerEndpoint that the DefaultJmsListenerContainerFactory using to initiate the container. But I am unable to find how to set it. Please see below what I did so far.
beanDefinitionRegistry.registerBeanDefinition("messageListenerContainer",
BeanDefinitionBuilder.rootBeanDefinition(DefaultJmsListenerContainerFactory.class)
.addPropertyReference("connectionFactory", "queueConnectionFactory")
.addPropertyReference("destinationResolver", "jndiDestinationResolver")
.addPropertyValue("concurrency", concurrency)
.addPropertyValue("sessionAcknowledgeMode", Session.AUTO_ACKNOWLEDGE)
.getBeanDefinition()
);
But as you can see I can not set the queue endpoint for listening. How can I do that from here?

Difference between DefaultJMSConnectionFactory and JmsXA

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

How to test WSO2 Message Broker with JMeter

I'm having some issues getting JMeter to work against the WSO2 Message Broker using the JMS Publisher. I had JMeter working against ActiveMQ but I'm still new with the tool.
I copied the client libraries over to jmeter wso2mb-2.0.1\client-lib to apache-jmeter-2.9\lib
andes-client-0.13.wso2v4.jar
geronimo-jms_1.1_spec-1.1.0.wso2v1.jar
Settings:
Context Factory : org.wso2.andes.jndi.PropertiesFileInitialContextFactory
Provider Url : amqp://admin:admin#clientID/carbon?brokerlist='tcp://localhost:5672'
Connection Factory : qpidConnectionfactory
...also tried several other values
Destination: dynamicQueues/test
The error I'm getting is on the Connection Factory field.
I've tried several different values all of which generate a naming error like there is a setting missing.
When I leave it blank I get:
javax.naming.NamingException: Expected javax.jms.ConnectionFactory, found org.wso2.andes.jndi.ReadOnlyContext
Does anyone know what I'm missing here?
Suspect it's something simple.
I found the problem.
In short the qpid context factory org.wso2.andes.jndi.PropertiesFileInitialContextFactory does not use fields the same way as the activeMQ context factory org.apache.activemq.jndi.ActiveMQInitialContextFactory.
While ActiveMQ allows you to not use a separate properties file with Jmeter, Qpid does not.
Jmeter JMS Publisher:
Context Factory : org.wso2.andes.jndi.PropertiesFileInitialContextFactory
Provider Url : nameOfYouFile.properties
Connection Factory : qpidConnectionfactory
Destination : <QueuePropertyName>
nameOfYouFile.properties:
connectionfactory.qpidConnectionfactory = amqp://admin:admin#clientID/carbon?brokerlist='tcp://localhost:5672'
queue.JMeterQueue = JMeterQueue
Reference:
Qpid Wiki

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

Unit-Of-Order in WLI JMSControl

One of our clientes is intented to use the Unit-Of-Order Weblogic Server Feature (UOO).
Everything is OK using UOO in pure java code for sending JMS Messages with custom UOO Names, as well as propagating the UOO Name in Aqualogic Service Bus from the Proxy Service to a Business Service (both using JMS as the transfer protocol).
However, using UOO in Weblogic Integration along with WLI JMSControl, does no work properly.
Consider this code:
#com.bea.control.JMSControl.Properties(value = {
#com.bea.control.JMSControl.PropertyValue(name = "JMS_BEA_UnitOfOrder", value = "MyUOONameFromWLI"),
#com.bea.control.JMSControl.PropertyValue(name = "MyCustomProperty", value = "MyCustomValue") })
public void sendTextMessage(String payload);
It sends the property MyCustomProperty to the JMS consumer, but the property JMS_BEA_UnitOfOrder - related to UOO Name - is ignored. The default User-generated UOO name is used instead.
So, how to customize my UOO Name using Weblogic JMSControl?
I've found that it has no support!

Resources