UnSatisfied Link Exception While sending a message to ibm-mq - java

I am new to MQ, I have a requirement where in I have to send a mq message from 1 system to another. The Message queue and Queue Manager is Set up at the server, and i only have the qname and the mqmanager name,I have written the following code to create a connection to mq, but i am getting this Exception:
UnsatisfiedLinkError: mqjbnd (Not found in java.library.path)
The code is:
package com.demo.mqsamplimport com.ibm.mq.MQC;
import com.ibm.mq.MQEnvironment;
import com.ibm.mq.MQException;
import com.ibm.mq.MQGetMessageOptions;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.MQConstants;
public class MQSample {
private static final String qManager = "(MyQueueManagerName)";
private static final String qName = "(MyQueueName)";
public static void putGet(String args[]) {
try {
MQQueueManager qMgr = new MQQueueManager(qManager);
int openOptions = MQConstants.MQOO_OUTPUT;
MQQueue queue = qMgr.accessQueue(qName, openOptions);
MQMessage msg = new MQMessage();
msg.writeString("Hello World!");
MQPutMessageOptions pmo = new MQPutMessageOptions();
queue.put(msg, pmo);
}
catch (MQException ex) {
ex.printstacktrace();
}
catch (java.io.IOException ex) {
ex.printstacktrace(););
}
}
}
can anyone please help me on this.

UnsatisfiedLinkError: mqjbnd (Not found in java.library.path) error is normally caused when you try to make a binding mode connection to IBM MQ Queue Manager hosted on the same server and the IBM MQ Classes for Java can not locate the library mqjbnd. If you do not specify a hostname and channel name for IBM MQ Classes for Java to use to connect, they default to a binding mode connection.
If your applications runs on the same server as the IBM MQ Queue Manager then you would need to tell the client how to find the mqjbnd libraries (on Linux this is /opt/mqm/java/lib) with one of the following methods:
set the LIBPATH environment variable for example on Linux bash export LIBPATH=/path/to/library
With the command line option -Djava.library.path=/path/to/library
Programmatically with System.setProperty("java.library.path", "/path/to/library");
If you are trying to connect to a IBM MQ Queue Manager hosted on a remote server I agree with #user7790438 that you would need to provide MQ with the details on how to connect to the remote queue manager. The MQEnvironment is global and not thread safe. You should use a hashtable to pass these values for example:
import java.util.Hashtable;
private static String host = "dns.name";
private static int port = 1414;
private static String channel = "MQ.SVRCONN.CHL";
Hashtable properties = new Hashtable<String, Object>();
properties.put("hostname", host);
properties.put("port", port);
properties.put("channel", channel);
MQQueueManager qMgr = new MQQueueManager(qManager, properties);
You do not mention what version of IBM MQ the queue manager is, or what version of IBM MQ classes for Java jar files you are referencing. Other details can be passed via the hash table, for example if you are using IBM MQ v8 or later Classes for Java and connecting to a IBM MQ v8 or later Queue Manager you may need to pass a UserID and Password, this would be accomplished by adding the following to the has table:
private static String user = "UserID";
private static String password = "Password";
properties.put(MQConstants.USE_MQCSP_AUTHENTICATION_PROPERTY, true);
properties.put(MQConstants.USER_ID_PROPERTY, user);
properties.put(MQConstants.PASSWORD_PROPERTY, password);
Please note that per the IBM v9.0 Knowledge center page "Deprecated, stabilized and removed features", IBM MQ Classes for Java have been Stabilization as of v8.0. This means that no further enhancements will be made and eventually IBM will deprecated the IBM MQ Classes for Java. You may want to write your application using the IBM MQ classes for JMS which has no support restrictions.
Stabilization of IBM MQ classes for Java
IBM will make no further enhancements to the IBM MQ classes for Java and they are functionally stabilized at the level shipped in IBM MQ Version 8.0. Existing applications that use the IBM MQ classes for Java will continue to be fully supported, but this API is stabilized, so new features will not be added and requests for enhancements rejected. Fully supported means that defects will be fixed together with any changes necessitated by changes to IBM MQ System Requirements.

You instantiated MQQueueManager before setting MQEnvironment's hostname and channel.
Just try add this:
MQEnvironment.hostname = "mq hostname";
MQEnvironment.channel = "mq channel";
Before:
MQQueueManager qMgr = new MQQueueManager(qManager);

Related

No Node Available Exception Elasticsearch 5.0.2

First for all, i'm sorry for my english.
I have a problem with Java API Transport Client. I have one master node and three data nodes. Version of my Elasticsearch is 5.0.2 and i use 5.0.2 API.
I try to connect to my cluster with Transport Client and then i response
Exception in thread "main" NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{8SAZOxXXTU61DuDDMN-vGw}{XX.XX.X.XXX}{XX.XX.X.XXX:9300}, {#transport#-2}{Fv3729YgTGClRBo5T2mWpA}{XX.XX.X.XXX}{XX.XX.X.XXX:9300}, {#transport#-3}{Fr98ApBbRv29Xv6Mc8L4TQ}{XX.XX.X.XXX}{XX.XX.X.XXX:9300}, {#transport#-4}{JOmpSH4LRzuP_XInxQtD9Q}{XX.XX.X.XXX}{XX.XX.X.XXX:9300}]]
at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:328)
at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:226)
at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:59)
at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:339)
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:403)
at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:80)
at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:54)
at org.elasticsearch.action.ActionRequestBuilder.get(ActionRequestBuilder.java:62)
at nn.Main.main(Main.java:57)
That is my code of client:
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.xpack.client.PreBuiltXPackTransportClient;
public class Main {
private static String[] hosts = new String[] {
"XX.XX.X.XXX"
,"XX.XX.X.XXX"
,"XX.XX.X.XXX"
,"XX.XX.X.XXX"
};
private static final Settings settings = Settings.builder()
.put("cluster.name", "myCluster")
.put("client.transport.sniff", true)
.put("transport.tcp.port", 9300)
.put("xpack.security.user", "transport_client_user:changeme")
.build();
private static final String index = "myIndex";
private static final String type = "myType";
private static TransportClient client;
public static void main(String[] args) throws UnknownHostException {
InetSocketTransportAddress[] ista = new InetSocketTransportAddress[hosts.length];
for (int i = 0; i < hosts.length; i++) {
ista[i] = new InetSocketTransportAddress(InetAddress.getByName(hosts[i]), 9300);
}
client = new PreBuiltXPackTransportClient(settings).addTransportAddresses(ista);
SearchRequestBuilder rb = client
.prepareSearch(index)
.setTypes(type)
.setSearchType(SearchType.DEFAULT)
.setQuery(QueryBuilders.termQuery("_id", 3524598));
SearchResponse sResponse = rb.get();
System.out.println(sResponse.toString());
}
}
Port for transport client - 9300, all my nodes communicate under this port. I saw a lot like my question, and i trying to follow the advice contained in them. But i have the same exception.
If need more information or any files or settings of my Elastic - i'm ready to answer.
If it is important this is content of elasticsearch.yml
cluster.name: myCluster
node.name: elastic-0
path.data: /var/db/elasticsearch
path.logs: /var/log/elasticsearch
path.scripts: /usr/local/libexec/elasticsearch
network.host: _vmx0_
node.master: true
node.data: false
node.ingest: false
node.attr.rack_id: rack_one
cluster.routing.allocation.awareness.attributes: rack_id
discovery.zen.minimum_master_nodes: 3
discovery.zen.ping.unicast.hosts: ["XX.XX.X.XXX","XX.XX.X.XXX","XX.XX.X.XXX","XX.XX.X.XXX","XX.XX.X.XXX"]
bootstrap.memory_lock: false
xpack.monitoring.exporters:
id1:
type: http
host: ["XX.XX.X.XXX:9200"]
auth.username: remote_monitor
auth.password: changeme
I tried to change TransportClient on just Client, and disable client.transport.sniff but without result.
I will be very gratefull for any help or ideas.
I found the reason for which i received "NoNodeAvailableException".
The reason is transport_client's role does not grant permission to view the data in all indices on default.
And i will to built my role for the access to data in indices.
Link: https://www.elastic.co/guide/en/x-pack/5.0/built-in-roles.html
This exception usually occurs when we try to use ES with TranscientClient (9300) and not with an API (9200).
These could be the reasons behind this:
Our IP address or the port that is provided is wrong. By default, the transport communication happens via 9300 until and unless we explicitly change in the elastisearch.yml
The IP address and the port is not reachable from the machine where we are running the Java Application. The ES machine is simply not reachable from Client Machine so we need to open the port and IP to the client.
If we change the 'transport.host' then ES considers as a prod environment and makes bootstrap checks. But in the scenario where the environment is not prod and we are running ES in one machine and trying to hit it from another machine with a transport client (Java app) then we can just add 'discovery.type: single-node'.
Change the Elastic Search yaml as follows:
cluster.name: elasticsearch
node.name: node-1
transport.host: 0.0.0.0
transport.tcp.port: 9300
http.port: 9200
network.host: 0.0.0.0
discovery.type: single-node

JMS connection to a remote MQ with bindings

I want to configure a Java application to work with a JMS IBM MQ queue using the bindings file.
I am using the JMSDEMO application provided by IBM.
It works with a local MQ manager but I cannot make it connect to a remote one.
I've generated the bindings file on the remote machine and copied it to my machine.
I've changed the "localhost" in the bindings file to the remote machine name.
However, the app still thinks it should connect to a local QM.
(actually it ignores the hostname settings).
Here's the IBM demo code:
public static final String cfLookup = "JMSDEMOCF";
public static final String JNDITopic = "JMSDEMOTopic";
public static final String JNDIQueue = "JMSDEMOQueue";
public static final String icf ="com.sun.jndi.fscontext.RefFSContextFactory";
........
static String url = "file:C:\\JMSDEMO\\JNDI";
..........
Hashtable environment = new Hashtable();
environment.put(Context.INITIAL_CONTEXT_FACTORY, icf);
environment.put(Context.PROVIDER_URL, url);
ctx = new InitialDirContext( environment );
connFactory = (ConnectionFactory)ctx.lookup( cfLookup );
connection = connFactory.createConnection();
connection.start();
Here are some fragments of the bindings file (JMSDEMOCF is the name of the connection factory)
JMSDEMOCF/RefAddr/3/Content=<the remote machine name or IP; both ignored>
JMSDEMOCF/RefAddr/29/Content=<the remote machine name or IP; both ignored>(the remote port)
It also has the following line:
JMSDEMOCF/RefAddr/116/Type=XMSC_WMQ_LOCAL_ADDRESS
but deleting it changes nothing.
Create a new connection factory in your "bindings file" with MQ Explorer (why are you trying to edit the file by hand?), and specify the Transport option as MQ Client on this new connection factory (the default is Bindings, which is the local connection mode).
On the Connection tab specify the address of the QM, and on the Channels tab the server connection channel to be used to connect to the QM.
Use the new connection factory in your application when connecting from a remote host. You may need to include some additional MQ JARs in the classpath.

Websphere MQ unable to create initial JNDI context

I am trying to run a demo class (JMSJNDIProducer.java) that comes with Websphere MQ 7.0 installation at 'websphere installation location'\tools\jms\samples. I have Websphere up and running, below are my websphere configurations...
Queue Manager Name: JMSDEMO
Queue Manager Port: 1414
Channel (default): SYSTEM.DEF.CLNTCONN
Queue Name: JMSDEMO.QL
let me know if more info needed...
My code is failing during the initial context creation, I'm very new to Websphere MQ and not sure what the initialContextUrl needs to be?
public class JMS_JNDI_Websphere_Sample {
private static String initialContextUrl = "tcp://localhost:1414";
public static void main(String args[]) {
// Instantiate the initial context
String contextFactory = "com.sun.jndi.fscontext.RefFSContextFactory";
Hashtable<String, Object> environment = new Hashtable<String, Object>();
environment.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory);
environment.put(Context.PROVIDER_URL, initialContextUrl);
try {
Context context = new InitialDirContext(environment);
} catch (NamingException e) {
e.printStackTrace();
}
System.out.println("Initial context found!");
}
}
I am getting the below exception.
javax.naming.InvalidNameException: tcp://localhost:1414 [Root exception is java.net.MalformedURLException: unknown protocol: tcp]
at com.sun.jndi.fscontext.FSContextFactory.getFileNameFromURLString(FSContextFactory.java:119)
at com.sun.jndi.fscontext.RefFSContextFactory.createContext(RefFSContextFactory.java:41)
at com.sun.jndi.fscontext.RefFSContextFactory.createContextAux(RefFSContextFactory.java:47)
at com.sun.jndi.fscontext.FSContextFactory.getInitialContext(FSContextFactory.java:49)
at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:667)
at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:288)
at javax.naming.InitialContext.init(InitialContext.java:223)
at javax.naming.InitialContext.<init>(InitialContext.java:197)
at javax.naming.directory.InitialDirContext.<init>(InitialDirContext.java:82)
at com.hcsc.jms.websphere.jndi.JMS_JNDI_Websphere_Sample.main(JMS_JNDI_Websphere_Sample.java:32)
Caused by: java.net.MalformedURLException: unknown protocol: tcp
at java.net.URL.<init>(URL.java:574)
at java.net.URL.<init>(URL.java:464)
at java.net.URL.<init>(URL.java:413)
at com.sun.jndi.fscontext.FSContextFactory.getFileNameFromURLString(FSContextFactory.java:117)
... 9 more
private static String initialContextUrl = "tcp://localhost:1414";
First off, I don't think "tcp" is a valid value and if it is, do you have something running on port 1414 to reply JNDI lookup requests?
Secondly, I think you are confusing MQ port 1414 with JNDI lookup.
Third, why don't you just follow the example in JmsJndiProducer.java and use a file-based JNDI.
i.e. Use MQ Explorer and select "JMS Administered Objects" then do file-based JNDI.
Once you create your file-based JNDI then that value for your initial context.
You need to separate out the concept of messaing as provided by the JMS API, and the lookup of an object via JNDI. As Roger said the issue is confusion between the MQ listener and the JNDI URL
JNDI is split into the interface used to bind and lookup objects in the directory and the 'service providers' that take the object and put into some persistent store. The com.sun.jndi.fscontext.RefFSContextFactory is a service provider that uses the file system, so the URL for this needs to be an EXISTING directory. When objects are 'bound' into that the .bindings file is created (or updated if objects are already there). You don't need to create the .bindings file; that file is created for you by the File System Context. Also don't modify this by hand.
Typically you would use a LDAP backed JNDI service provider for production usage. The 'lookup' APIs used in the application are the same; what would change are the provider URL (as the location of the LDAP server would be provided) and possible the object name.
Would suggest reviewing Oracle's JNDI tutorial ..

Java client listening to WebSphere MQ Server?

I need to write a Java client listening to WebSphere MQ Server. Message is put into a queue in the server.
I developed this code, but am not sure it is correct or not. If correct, then how can I test it?
This is a standalone Java project, no application server support. Which jars I should put into classpath?
I have the MQ settings, where I should put into my codes? Standard JMS can skip these settings? confusing ....
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class Main {
Context jndiContext = null;
QueueConnectionFactory queueConnectionFactory = null;
QueueConnection queueConnection = null;
QueueSession queueSession = null;
Queue controlQueue = null;
QueueReceiver queueReceiver = null;
private String queueSubject = "";
private void start() {
try {
queueConnection.start();
queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = queueSession.createQueue(queueSubject);
MessageConsumer consumer = queueSession.createConsumer(destination);
consumer.setMessageListener(new MyListener());
} catch (Exception e) {
e.printStackTrace();
}
}
private void close() {
try {
queueSession.close();
queueConnection.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private void init() {
try {
jndiContext = new InitialContext();
queueConnectionFactory = (QueueConnectionFactory) this.jndiLookup("QueueConnectionFactory");
queueConnection = queueConnectionFactory.createQueueConnection();
queueConnection.start();
} catch (Exception e) {
System.err.println("Could not create JNDI API " + "context: " + e.toString());
System.exit(1);
}
}
private class MyListener implements MessageListener {
#Override
public void onMessage(Message message) {
System.out.println("get message:" + message);
}
}
private Object jndiLookup(String name) throws NamingException {
Object obj = null;
if (jndiContext == null) {
try {
jndiContext = new InitialContext();
} catch (NamingException e) {
System.err.println("Could not create JNDI API " + "context: " + e.toString());
throw e;
}
}
try {
obj = jndiContext.lookup(name);
} catch (NamingException e) {
System.err.println("JNDI API lookup failed: " + e.toString());
throw e;
}
return obj;
}
public Main() {
}
public static void main(String[] args) {
new Main();
}
}
MQ Queue setting
<queue-manager>
<name>AAA</name>
<port>1423</port>
<hostname>ddd</hostname>
<clientChannel>EEE.CLIENTS.00</clientChannel>
<securityClass>PKIJCExit</securityClass>
<transportType>1</transportType>
<targetClientMatching>1</targetClientMatching>
</queue-manager>
<queues>
<queue-details id="queue-1">
<name>GGGG.NY.00</name>
<transacted>false</transacted>
<acknowledgeMode>1</acknowledgeMode>
<targetClient>1</targetClient>
</queue-details>
</queues>
There is an article with sample code Running a standalone Java application on WebSphere MQ V6.0 which walks you through most of your questions, including how you might test with a free WMQ trial install. The main difference (as discussed in the comments) to v7 or v7.1 is that there is no broker component to start if you want to use topics. Other than that, the article should work fine with the current WMQ client and/or server.
In addition, please refer to the WebSphere MQ Using Java manual (v7.0 client) or the Using WebSphere MQ Classes for Java manual (v7.1 client) for the appropriate CLASSPATH and other settings for your client. Remember to use the Infocenter appropriate to your client version and not to the server version. You can mix and match client and server version but you get only the features supported by the server. For example, using the WMQ v7.1 client with the WMQ v7.0 server is perfectly valid.
Finally, there are a number of sample programs supplied with the free client download that do exactly what you are describing. Some use JNDI to lookup the WMQ resources, others use Java methods and can be populated with standard Java property files. The ones with a -nojndi option show how to initialize your WMQ objects in the code at run time. These are under
[WMQ Install path]\tools\wmqjava\samples
...in the latest Windows client install (SupportPac MQC71). You can also use the v7.0 client (SupportPac MQC7). I would recommend using the samples to get started rather than starting from scratch. Why reinvent the wheel, right?
In addition to the many sample programs, the vendor install includes all of the requisite jar files. Note that what goes in the CLASSPATH changes by WMQ client version so refer to the Infocenter. The later versions are much simpler and require only a couple of jar files in the CLASSPATH.
If you want to download the WMQ trial for testing and do not have Administrator rights on your Windows workstation, you can install it easily on a RedHat or SUSE virtual machine. With a bit of massaging you can also easily install on Ubuntu as described in an Andy Piper blog post.
If you have the option, I would recommend that you introduce the Spring Framework to handle the JMS communication. That way you only need to write your business logic and can leave the error handling up to Spring.
Spring JMS
Download the latest Spring JARS and look at configuring a DefaultMessageListenerContainer for your application. You will then write your own POJO (plain old java object) with an onMessage() event that gets called everytime a new message arrives.
I found this tutorial that you may find useful to start with
There is a small client application that I developed in JavaFx2 for windows and Mac osx. It's available on source forge (https://sourceforge.net/projects/mqconsole).
You can see an example of listening to a queue for new messages.
The program lists the queues, the messages in each queue, view the details of the message and send a message to a queue and listen to the response.
You can check out the code, use it and improve it.

Send to MQ from java always uses default installed mqm userid for IBM MQ version 6.0

Our code runs in weblogic and we MQ 6.0. No matter if I use the default createQueueConnection() or createQueueConnection("myuserid","mypassword") it always seems to use userid mqm. See code below.
When I connect from version 6.0 to an older mq installion 5 it seems to throw the following error javax.jms.JMSSecurityException: MQJMS2013: invalid security authentication supplied for MQQueueManager using the default createQueueConnection() unless I send a blank userid/password as in createQueueConnection("","")
How can I get myuserid to be send instead ?
Hashtable properties = new Hashtable(2);
properties.put(Context.PROVIDER_URL,context);
properties.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory");
InitialContext ctx = new InitialContext(properties);
QueueConnectionFactory qcf = (QueueConnectionFactory) ctx.lookup("QCF");
QueueConnection qc = qcf.createQueueConnection();
javax.jms.Queue q = (javax.jms.Queue) ctx.lookup("MYQUEUE");
QueueSession qs = qc.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
TextMessage tm = qs.createTextMessage();
tm.setText(outString);
QueueSender sender = qs.createSender(q);
sender.send(tm);
sender.close();
qs.close();
qc.close();
If you are setting the ID in the createQueueConnection, rest assured, it is being presented to the queue manager. The problem you are seeing is that the SVRCONN channel definition on the QMgr has the value MCAUSER('mqm') hard coded. This overrides any value presented by the client app.
A couple of things to note here.
Although you can send the ID and password, WMQ accepts these at face value. The fields exist to make the credentials available for a channel exit that can validate them. Without such an exit the channel just runs as whatever ID the app claims to be and the password is ignored.
For the reason stated above, I always tell people not to trust the credentials presented unless they have such an exit. The administrator must code the appropriate value into the MCAUSER.
The administrative ID ('mqm' on UNIX flavors) is NOT the appropriate value. It confers administrative authority to anyone connecting on that channel.
For a LOT more on this topic and pointers to the WMQ security presentation and WMQ Security Lab guide from IMPACT, please see this SO question.

Categories

Resources