How to connect to the MQ Server QUEUE MANAGER using MQ Client - ibm-mq

I was try to send message to the MQ Server using the MQ Client
The error is:- A WebSphere MQ Error occurred : Completion Code 2 Reason Code 2058.I know this reason code because of the wrong Queue Manager Name..But the Queue Manager Name is correct...
After installed the WebSphere MQ Client I just run the command:
SET MQSERVER=QM_ORANGE/TCP/IPADDRESS(PORT NUMBER)
and run this program
public class MQSample {
// code identifier
static final String sccsid = "#(#) MQMBID sn=p750-002-131001_DE su=_FswqMCqGEeOZ3ui-rZDONA pn=MQJavaSamples/wmqjava/MQSample.java";
// define the name of the QueueManager
private static final String qManager = "QM_ORANGE";
// and define the name of the Queue
private static final String qName = "Q1";
/**
* Main entry point
*
* #param args - command line arguments (ignored)
*/
public static void main(String args[]) {
try {
// Create a connection to the QueueManager
System.out.println("Connecting to queue manager: " + qManager);
MQQueueManager qMgr = new MQQueueManager(qManager);
// Set up the options on the queue we wish to open
//int openOptions = MQConstants.MQOO_INPUT_AS_Q_DEF | MQConstants.MQOO_OUTPUT;
int openOptions = MQConstants.MQOO_OUTPUT;
// int openOptions1 = MQConstants.MQOO_INPUT_AS_Q_DEF;
// Now specify the queue that we wish to open and the open options
System.out.println("Accessing queue: " + qName);
MQQueue queue = qMgr.accessQueue(qName, openOptions);
//MQQueue queue1 = qMgr.accessQueue(qName, openOptions1);
// Define a simple WebSphere MQ Message ...
MQMessage msg = new MQMessage();
// ... and write some text in UTF8 format
msg.writeUTF("Hello, World!");
// Specify the default put message options
MQPutMessageOptions pmo = new MQPutMessageOptions();
// Put the message to the queue
System.out.println("Sending a message...");
queue.put(msg, pmo);
//
openOptions = MQC.MQOO_INQUIRE + MQC.MQOO_FAIL_IF_QUIESCING
+ MQC.MQOO_INPUT_SHARED;
queue = qMgr.accessQueue("QM_APPLE", openOptions,
null, // default q manager
null, // no dynamic q name
null); // no alternate user id
System.out.println("MQRead v1.0 connected.\n");
int depth = queue.getCurrentDepth();
System.out.println("Current depth: " + depth + "\n");
if (depth == 0) {
return;
}
MQGetMessageOptions getOptions = new MQGetMessageOptions();
getOptions.options = MQC.MQGMO_NO_WAIT + MQC.MQGMO_FAIL_IF_QUIESCING
+ MQC.MQGMO_CONVERT;
while (true) {
MQMessage message = new MQMessage();
try {
queue.get(message, getOptions);
byte[] b = new byte[message.getMessageLength()];
message.readFully(b);
System.out.println(new String(b));
message.clearMessage();
} catch (IOException e) {
System.out.println("IOException during GET: " + e.getMessage());
break;
} catch (MQException e) {
if (e.completionCode == 2
&& e.reasonCode == MQException.MQRC_NO_MSG_AVAILABLE) {
if (depth > 0) {
System.out.println("All messages read.");
}
} else {
System.out.println("GET Exception: " + e);
}
break;
}
}
queue.close();
//_queueManager.disconnect();
// Disconnect from the QueueManager
System.out.println("Disconnecting from the Queue Manager");
qMgr.disconnect();
System.out.println("Done!");
}
catch (MQException ex) {
System.out.println("A WebSphere MQ Error occured : Completion Code " + ex.completionCode
+ " Reason Code " + ex.reasonCode);
ex.printStackTrace();
for (Throwable t = ex.getCause(); t != null; t = t.getCause()) {
System.out.println("... Caused by ");
t.printStackTrace();
}
}
catch (java.io.IOException ex) {
System.out.println("An IOException occured whilst writing to the message buffer: " + ex);
}
return;
}
}

You have set the MQSERVER environment variable. MQ C Client understands this environment variable and accordingly connects to queue manager running on the machine specified in IP address. MQ Java does not behave in the same way.
In your application you have specified just the queue manager name in MQQueueManager constructor. This mean application wants to connect to queue manager running on the same machine via server bindings connection.
You could do as below to connect to queue manager: (change the host, port, channel and queue manager name). Note the sample is written with MQ v8 Java client.
Hashtable properties = new Hashtable<String, Object>();
properties.put(MQConstants.HOST_NAME_PROPERTY, "qm.mycomp.com");
properties.put(MQConstants.PORT_PROPERTY, 1414);
properties.put(MQConstants.CHANNEL_PROPERTY, "APP.SVRCONN");
properties.put(MQConstants.USE_MQCSP_AUTHENTICATION_PROPERTY,"true");
properties.put(MQConstants.USER_ID_PROPERTY, "myuserid");
properties.put(MQConstants.PASSWORD_PROPERTY, "passw0rd");
/**
* Connect to a queue manager
*/
MQQueueManager queueManager = new MQQueueManager("QM", properties);
Update
So you don't want to hard code connection parameters in your program? You can use the MQSERVER environment variable it self, get it, parse it and the connection parameters. You can also use a configuration file or a LDAP server to pull the connection information.
Update II
You have not read the MQ documentation at all. MQ Client is a set of libraries/jars/.net assemblies etc which expose APIs in different languages. You develop application using these APIs to communicate with queue manager. That is what you have done in your program above. Without these libraries you can't connect to a queue manager (many people think queue manager as server). When your application runs on the same machine as the queue manager, it is possible to communicate with queue manager over shared memory. But when running on different machine the communication is over TCP/IP (or SNA).
Hope this clears the confusion.

Related

JMS message delivery delay after calling setRollbackOnly

I am implementing an JMS MDB solution for invoking webservices that would be triggered from several points in the application. For the sake of validating my solution I am just passing Integer objects right now. I am forcing the code to redeliver messages when the Integer is greater than 5. However, if the message has been redelivered twice it should be ignored/commit. The wait time configured in Websphere is 5 mins, and the max failed deliveries per message is 0 (under Exception destination on Buses -> {bus} -> Destinations -> {destination}).
The problem is when message for object 6 is sent back to queue for re-delivery after 5 mins, the messages for 7, 8, 9... are also put on hold until 6 is redelivered. Although I know JMS does not guarantees message delivery order, but usually it is FIFO. But once a message has been sent back to the queue and redelivered, the order of remaining messages is not sequential. i.e. it is something like 6, 8, 9, 7.
Under JMS Activation specifications Maximum batch size is 1 and Maximum concurrent MDB invocations per endpoint is 10.
Any idea how to deal with new messages that are blocked due to message on hold? I referred the question at this link, it says that the queue should not be blocked.
JMS and MDB with setRollbackOnly
Also please provide suggestions on maintaining message order.
Snippet of code:
public void onMessage(javax.jms.Message msg) {
try {
if (msg instanceof ObjectMessage) {
ObjectMessage objMsg = (ObjectMessage)msg;
Object obj = objMsg.getObject();
UserTransaction userTxn = getMessageDrivenContext().getUserTransaction();
userTxn.begin();
InitialContext initialContext = new InitialContext();
ConnectionFactory cf = (ConnectionFactory) initialContext.lookup("jms/cf");
javax.jms.Connection conn = cf.createConnection();
Session jmsSession = conn.createSession(true, -1);
Queue queue = (Queue) initialContext.lookup("jms/queue1");
QueueBrowser queueBrowser = jmsSession.createBrowser(queue);
Enumeration enumeration = queueBrowser.getEnumeration();
while (enumeration.hasMoreElements()) {
System.out.println("Browse [" + enumeration.nextElement() + "]");
}
if ((Integer)obj >= 6) {
int count = Integer.valueOf(msg.getStringProperty("JMSXDeliveryCount"));
if (count > 2) {
System.out.println("********** max rollback");
userTxn.commit();
} else {
System.out.println("********** rollback");
userTxn.setRollbackOnly();
}
} else {
System.out.println("********** commit");
userTxn.commit();
}
} else {
}
} catch (Exception ex) {
ex.printStackTrace();
throw new EJBException("Transaction failed: " + ex.getMessage());
} catch (Throwable t) {
}
}

Set x-first-death-reason or custom header while rejecting message (SpringAMQP)

I have SpringBoot AMQP application where I have dead letter setup for a queue. Is there anyway to set custom message for x-first-death-reason while throwing AmqpRejectAndDontRequeueException
I have this right now
#RabbitListener(bindings = #QueueBinding(
value = #Queue(value = "core.queue",
durable = "true",
arguments = {
#Argument(name = "x-dead-letter-exchange", value = RabbitConfiguration.ERROR_EXCHANGE),
#Argument(name = "x-dead-letter-routing-key", value = RabbitConfiguration.ERROR_ROUTING_KEY)
}
),
exchange = #Exchange(value = "core.exchange"),
key = "core.route")
)
public void errorListener(final Message message) {
try {
.......
} catch (IOException e) {
// I would like to set value for x-first-death-reason or set
// custom header if possible.
throw new AmqpRejectAndDontRequeueException(e.getMessage());
}
}
No; the amqp protocol does not allow the consumer to modify a rejected message. You would have to publish to the DLQ yourself instead of having RabbitMQ route it.

How to implement a distributed priority queue without using Zookeeper?

I want to implement a distributed priority queue without using Zookeeper?
If you know how to communicate between client and server (e.g. with TCP sockets) it should be straightforward. The server contains a thread safe implementation of the Priority Queue, hence providing an "interface". Clients connect to the server and uses this "interface".
Server
The server must provide a priority queue interface (i.e. supporting add, peek, poll, ...). Important is that these methods must be thread safe ! So we will use PriorityBlockingQueue (which is synchronized) instead of PriorityQueue.
public class Server {
private static ServerSocket server_skt;
public PriorityBlockingQueue<Integer> pq;
// Constructor
Server(int port, int pq_size) {
server_skt = new ServerSocket(port);
this.pq = new PriorityBlockingQueue<Integer>(pq_size);
}
public static void main(String argv[]) {
Server server = new Server(5555, 20); // Make server instance
while(true) {
// Always wait for new clients to connect
try {
System.out.println("Waiting for a client to connect...");
// Spawn new thread for communication with client
new CommunicationThread(server_skt.accept(), server.pq).start();
} catch(IOException e) {
System.out.println("Exception occured :" + e.getStackTrace());
}
}
}
}
And this is how CommunicationThread class would look like
public class CommunicationThread extends Thread {
private Socket client_socket;
private InputStream client_in;
private OutputStream client_out;
private PriorityBlockingQueue<Integer> pq;
public CommunicationThread(Socket socket, PriorityBlockingQueue<Integer> pq) {
try {
this.client_socket = socket;
this.client_in = client_socket.getInputStream();
this.client_out = client_socket.getOutputStream();
this.pq = pq;
System.out.println("Client connected : " + client_socket.getInetAddress().toString());
} catch(IOException e) {
System.out.println("Could not initialize communication properly. -- CommunicationThread.\n");
}
}
#Override
public void run() {
boolean active = true;
while(active) {
int message_number = client_in.read(); // Listen for next integer --> dispatch to correct method
switch(message_number) {
case -1: case 0:
// Will stop the communication between client and server
active = false;
break;
case 1:
// Add
int element_to_add = client_in.read(); // read element to add to the priority queue
pq.add(element_to_add); // Note that a real implementation would send the answer back to the client
break;
case 2:
// Poll (no extra argument to read)
int res = pq.poll();
// Write result to client
client_out.write(res);
client_out.flush();
break;
/*
* IMPLEMENT REST OF INTERFACE (don't worry about synchronization, PriorityBlockingQueue methods are already thread safe)
*/
}
}
client_in.close();
client_out.close();
}
}
This class is listening to what the client is sending.
According to what the client sent, the server knows what to do, hence there is a mini protocol. That protocol is : when the client wants to invoke a method of the distributed priority queue, he sends an integer (e.g. 2 = poll()). The server reads that integer and knows which method to invoke.
Note that sometimes sending one integer is enough (see poll() example), but not always. Think for example of add() which has to specify an argument. The server will receive 1 from the client (i.e. add()) and will read a second integer (or any other object that has to be stored in the distributed priority queue).
Client
Based on the protocol, the server is offering the client an interface (e.g. 0 = stop communication, 1 = add() , ...). The client only has to connect to the server and send messages (respecting the procotol!) to it.
A client example :
public class PQ_Client {
private static Socket skt;
private InputStream in;
private OutputStream out;
private final int _STOP_ = 0, _ADD_ = 1, _POLL_ = 2; // By convention (protocol)
PQ_Client(String ip, int port) {
try {
this.skt = new Socket(ip, port);
this.in = skt.getInputStream();
this.out = skt.getOutputStream();
System.out.println("Connected to distributed priority queue.");
} catch(IOException e) {
System.out.println("Could not connect with the distributed priority queue : " + e.getStackTrace());
}
}
// Sort of stub functions
public void stop() {
out.write(_STOP_);
out.flush();
out.close();
}
public void add(Integer el) {
out.write(_ADD_); // Send wanted operation
out.write(el); // Send argument element
// Real implementation would listen for result here
out.flush();
}
public int poll() {
out.write(_POLL_);
out.flush();
// Listen for answer
return in.read();
}
/*
* Rest of implementation
*/
}
Note that thanks to these self made "stub functions" we can make a PQ_Client object and use it as if it was a priority queue (the client/server communication is hidden behind the stubs).
String ip = "...";
int port = 5555;
PQ_Client pq = new PQ_Client(ip , port);
pq.add(5);
pq.add(2);
pq.add(4);
int res = pq.poll();
Note that by using RPC (Remote Procedure Call) it could be easier (stub function generated automatically, ...).
In fact what we implemented above is a little RPC-like mechanism, as it does nothing else then sending a message to call a procedure (e.g. add()) on the server, serializing the result (not needed for integers), send it back to the client.

I/O error occurred when getting message queue from Websphere MQ

I am currently facing a problem right now wherein I am getting the error I/O error occurred. and I don't know how to pin point where the error occurred. This happened when I get a message queue from the queue. Below is the stack trace of the error.
StackTrace: at AlertTrigger.Data.ServiceAgents.WebSphereAgent.GetMessageQueue(String queueManagerName, String queueName)
at AlertTrigger.Business.AlertTriggerComponent.QueueListener()
Below is the code for the GetMessageQueue:
public string GetMessageQueue(string queueManagerName, string queueName)
{
MQQueueManager mqQueueManager;
MQQueue storeQueue;
string result = string.Empty;
try
{
MQMessage mqMessage = new MQMessage();
MQGetMessageOptions mqGetMessageOption = new MQGetMessageOptions();
mqGetMessageOption.Options = MQC.MQGMO_WAIT;
mqGetMessageOption.WaitInterval = 15000;
mqQueueManager = new MQQueueManager(queueManagerName);
storeQueue = mqQueueManager.AccessQueue(queueName, MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING);
storeQueue.Get(mqMessage, mqGetMessageOption);
result = mqMessage.ReadString(mqMessage.DataLength);
}
catch (MQException MQEx)
{
// Close request Queue if still opened
if (storeQueue != null && storeQueue.OpenStatus)
storeQueue.Close();
// Close Queue manager if still opened
if (mqQueueManager != null && mqQueueManager.OpenStatus)
mqQueueManager.Close();
throw new MQAdapterException(MQEx.Reason.ToString());
//throw new MQAdapterException("Error Code: " + MQAdapterErrorReasons.GetMQFailureReasonErrorCode(MQEx.Reason));
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
finally
{
// Close request Queue if still opened
if (storeQueue != null && storeQueue.OpenStatus)
storeQueue.Close();
// Close Queue manager if still opened
if (mqQueueManager != null && mqQueueManager.OpenStatus)
mqQueueManager.Close();
}
return result;
}
I hope you can help me on this as I am quite new to WebSphere MQ.
Is this a Java or C# application? If it is Java, you should do:
result = mqMessage.ReadString(mqMessage.getMessageLength());

Connect to an oracle db in jdbc over an SSH tunnel

Currently we have to tunnel over SSH to access our Oracle database. In order to do this we have to make sure than putty or an equivalent program/script is running on the server doing this tunelling before the application is deployed to Tomcat/Glassfish/etc.
Has anybody found a way to have java handle this tunneling transparently? Perhaps a jdbc driver than itself wraps another jdbc drive handling the tunnelling for you right in Java?
My solution was to use Jsch from JCraft http://www.jcraft.com/jsch/ to open a tunnel when my application server starts up. I close the tunnel when the application server shuts down. I do this via a servlet context listener.
int findUnusedPort() {
final int startingPort = 1025;
final int endingPort = 1200;
for (int port = 1025; port < 1200; port++) {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(port);
return port;
} catch (IOException e) {
System.out.println("Port " + port + "is currently in use, retrying port " + port + 1);
} finally {
// Clean up
if (serverSocket != null) try {
serverSocket.close();
} catch (IOException e) {
throw new RuntimeException("Unable to close socket on port" + port, e);
}
}
}
throw new RuntimeException("Unable to find open port between " + startingPort + " and " + endingPort);
}
private Session doSshTunnel(int tunnelPort) {
// SSH Tunnel
try {
final JSch jsch = new JSch();
sshSession = jsch.getSession("username", "sshhost", 22);
final Hashtable<String, String> config = new Hashtable<String, String>();
config.put("StrictHostKeyChecking", "no");
sshSession.setConfig(config);
sshSession.setPassword("password");
sshSession.connect();
int assigned_port = sshSession.setPortForwardingL(tunnelPort, remoteHost, remotePort);
return sshSession;
} catch (Exception e) {
throw new RuntimeException("Unable to open SSH tunnel", e);
}
}
I have used Apache MINA SSHD for a project a while back and I remember that there was support ofr opening tunnels.
You can check out http://mina.apache.org/sshd/ for more info.
Other options are discussed on this quesiton : SSH library for Java

Resources