Connecting to a JMS Queue using a file system based Initial Context - jms

Using Websphere MQ Explorer, I have created a new file system based initial contextfor JMS. Using the new initial context, I have created a JMS queue to connect to an existing queue (currently accessed using a non java based framework).
Within the application code, I can succesfully connect to the context, as follows:
properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
properties.put(Context.PROVIDER_URL, "file:C://folder-name//");
try {
val ctx = new InitialContext(properties)
Next, I create a QueueConnectionFactory:
val qcf = (ctx.lookup("com.ibm.mq.jms.MQQueueFactory")).asInstanceOf[QueueConnectionFactory]
However, this throws the following exception:
javax.naming.NameNotFoundException: com.ibm.mq.jms.MQQueueFactory
at com.sun.jndi.fscontext.RefFSContext.getObjectFromBindings(RefFSContext.java:400)
at com.sun.jndi.fscontext.RefFSContext.lookupObject(RefFSContext.java:327)
at com.sun.jndi.fscontext.RefFSContext.lookup(RefFSContext.java:146)
at com.sun.jndi.fscontext.FSContext.lookup(FSContext.java:127)
at javax.naming.InitialContext.lookup(InitialContext.java:411)
I used com.ibm.mq.jms.MQQueueFactory as the connection factory name, because in the .bindings file, there is the following line:
MY.QUEUE/FactoryName=com.ibm.mq.jms.MQQueueFactory
But that throws an exception.
Where would the correct connection factory name be defined?
Thanks

Problem solved - under the file based context (under JMS Administered Objects), a Connection Factory must be defined.

Related

Unable to establish connection using jms jndi

I am very new to JMS & JNDI, and I'm trying to receive message from a queue programatically, but I am not sure how I can connect to the server. I have Websphere console UI where I login to manage all my queues. This console UI is hosted at linux-server:7276. Below is the UI link
https://my-server:9043/ibm/console
I have referred to the sample classes from IBM MQ JmsJndiConsumer:
String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
String initialContextUrl = "ldap://my-server:9043"
Hashtable<String, String> environment = new Hashtable<String, String>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
environment.put(Context.PROVIDER_URL, initialContextUrl);
environment.put(Context.SECURITY_PRINCIPAL, userName);
environment.put(Context.SECURITY_CREDENTIALS, password);
InitialContext context = new InitialContext(environment);
It always throws an error in the context Connection or outbound has closed.
The queue I am trying to connect to has these details:
Connection factories : jms/atConnectionFactory
queue-manager : appit-node.Sit-TBus
Bus name : TBus
queue name : jms/appitone-event
Bootstrap Member : linux-server:7276
You're using my-server:9043 for both your HTTPS and LDAP server. Both of these can't be using the same port on the same machine so one of them must be wrong which is almost certainly why it's failing.

Is it possible to have a remote pooled JMS connection factory (WildFly 10)?

I have a remote java client which looks up a JMS connection factory on Wildfly 10, and everything works fine as expected. It is just a test program; a simple JMS chat system. When I start more than one instance of the chat client sometimes the following message appears:
WARN: AMQ212051: Invalid concurrent session usage. Sessions are not supposed to be used by more than one thread concurrently.
Followed by a trace.
Now I want to fix this warning, therefore I need a pooled connection factory. But the pooled connection factory isn't available remotely (and as I read it shouldn't be available remotely).
What can I do to fix this warning when I want to start multiple JMS chat clients locally?
I know that the error won't appear when I just different machines.
This is the working non-pooled remote code (but with warning)
final Properties properties = new Properties();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
properties.put(Context.PROVIDER_URL, "http-remoting://127.0.0.1:8080");
try {
context = new InitialContext(properties);
ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup("jms/RemoteConnectionFactory");
jmsContext = connectionFactory.createContext("quickstartUser", "quickstartPwd1!");
} catch (NamingException e) {
e.printStackTrace();
}
The problem isn't caused by not using a pooled connection factory and won't be solved by using a pooled connection factory. The problem is the way your application is using the same JMS session concurrently between multiple threads (as the WARN message indicates). The stack-trace which is logged will show you which class & method is triggering the WARN message.
You need to ensure that your application does not use the same JMS session concurrently between multiple threads. You can do this by giving each thread its own JMS session or by setting up concurrency controls around the session so that only one thread at a time can access it.

WebSphere wsadmin script to create custom properties for JMS provider

I have created a custom JMS provider in WebSphere 8. Now I want to add custom properties to this JMS provider, but the usual procedure does not work.
I created the JMS provider with the following commands (Jython):
server = AdminConfig.getid('/Cell:cell/Node:node0/Server:appserver/')
jms_provider = AdminConfig.create('JMSProvider', server, '[[name "ActiveMQ"] [externalInitialContextFactory "org.apache.activemq.jndi.ActiveMQWASInitialContextFactory"] [externalProviderURL "tcp://10.1.1.1:61616"]]')
Usually, I would get a custom property set in order to popultate it, but I just get "None":
wsadmin> print(AdminConfig.showAttribute(jms_provider, 'propertySet'))
(None)
Creating a new one does not work either:
wsadmin> AdminConfig.create('J2EEResourceProperty', jms_provider, [])
WASX7015E: Exception running command: "AdminConfig.create('J2EEResourceProperty', jms_provider, [])"; exception information:
com.ibm.ws.scripting.ScriptingException: WASX7129E: Cannot create objects of type "J2EEResourceProperty" in parents of type "JMSProvider"
How can I create the initial property set for a JMS provider?
Solution was to create a J2EEResourcePropertySet instead of a J2EEResourceProperty:
props = AdminConfig.create('J2EEResourcePropertySet', jms_provider, [])
AdminConfig.create('J2EEResourceProperty', props, '[[name "java.naming.queue.Queue1"] [value "Queue1"]]')

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.

Send message to MQ using Jmeter

I want to send message to a remote IBM MQ using Jmeter for performance testing. I went through this link. But it requires the JNDI specific details like, QueueConnection Factory, JNDI Name Request queue, Initial Context Factory & Provider URL. Whereas the queu details i have are Qmanager, Qname, hostname, channel, port as given in the code shared in this link. Do these properties have any relation? Can i configure the Jmeter JMS test using the queue details i have?
Thanks in advance.
The first link you gave has a description using Java JMS/MQ and the second shows Java MQ (non-JMS).
JMS is just an abstraction layer. In simple terms, JMS is like giving everything a nick-name. A QCF (QueueConnectionFactory) is simply an object that has all of the information to connect to a queue manager.
i.e.
DEFINE QCF(myQCF) QMANAGER(MQWT1) CHANNEL(TEST.CHL) HOSTNAME(127.0.0.1) PORT(1415) TRANSPORT(CLIENT) FAILIFQUIESCE(YES)
A JMS queue is just a nick-name to an MQ queue.
DEFINE Q(test.q) QUEUE(TEST.Q1) QMANAGER(MQWT1) TARGCLIENT(JMS) FAILIFQUIESCE(YES)
Therefore, in your JMS code you simply reference your QCF (i.e. myQCF) and the JMS queue (i.e. test.q) and you are good to go.
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
env.put(Context.PROVIDER_URL, ""file:/C:/JNDI-Directory");
try
{
Context ctx = new InitialContext(env);
QueueConnectionFactory cf = (QueueConnectionFactory) ctx.lookup("myQCF");
Queue q = (Queue) ctx.lookup("test.q");
}
catch (NamingException e)
{
System.err.println(e.getLocalizedMessage());
e.printStackTrace();
}
It can be done via the beanshell as well. You can directly access the queue manager via the api, or via exposing the queue via a jms binding. The first is more simple and does not require the MQ client installation.

Resources