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.
Related
everyone,
I have an application that we're switching to quarkus.
So far I could do a remote lookup via JNDI to a JMS queue in a weblogic. But it seems that Quarkus does not support JNDI anymore.
So my question is, how can I do the lookup on the remote queue in WLS?
My old code was like that
Hashtable<String, String> env = new Hashtable();
env.put("java.naming.factory.initial", "weblogic.jndi.WLInitialContextFactory");
env.put("java.naming.provider.url", url);
InitialContext context = new InitialContext(env);
ConnectionFactory connectionFactory = (ConnectionFactory) context.lookup(jmsConnectionFactory);
Destination destination = (Destination) context.lookup(jmsDestination);
connection = connectionFactory.createConnection();
session = connection.createSession(true, 1);
sender = session.createProducer(destination);
Quarkus indeed does not support JNDI.
JMS can be used via the Quarkus QPid extension.
You can read the documentation here and view a quickstart application here.
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.
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.
How to get Websphere MQ Queue depth in case of Multi Instanced environment.
For a single instance we are getting a queue depth using the MQManager like this:
#SuppressWarnings("unchecked")
private MQQueueManager createQueueManager() throws MQException {
MQEnvironment.channel = channel;
MQEnvironment.port = port;
MQEnvironment.hostname = host;
MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES);
return new MQQueueManager(manager);
}
For Websphere MQ in multi-instancing environment how to perform the same ?
You can do it either of these ways:
Use a load balancer which is capable of routing the TCP connections based on the availability of the queue manager instances behind it, and connect to the address of the load balancer instead of directly to the queue manager.
Use a Client Channel Definition Table to specify the parameters for the queue manager connection. You will need to configure a queue manager group containing the instances of your queue manager and connect using the CCDT:
https://www-01.ibm.com/support/knowledgecenter/SSFKSJ_7.1.0/com.ibm.mq.doc/ja11090_.htm
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.