Migration from mq version 7.0 to 7.5 - java

I am Migrating from Mq version 7.0 to 7.5 . I am able to receive messages through the inbound queues using ejb - Message Driven Beans(MDBs) but while posting the message after processing it on the. I am getting the IBM MQRC 2082 MQRC_UNKOWN_ALIAS_BASE_Q Exception.
This is the exception that I am getting :
Caused by: javax.jms.InvalidDestinationException: MQJMS2008: failed to
open MQ queue 'OFS.TIG_IND2NSE_MSG'.
at com.ibm.msg.client.wmq.v6.jms.internal.MQQueueServices.getQueueOpenException(MQQueueServices.java:901)
at com.ibm.msg.client.wmq.v6.jms.internal.MQQueueServices.getOutputQueue(MQQueueServices.java:727)
at com.ibm.msg.client.wmq.v6.jms.internal.JMSServicesMgr.getOutputQueue(JMSServicesMgr.java:210)
at com.ibm.msg.client.wmq.v6.jms.internal.MQSession.createQProducer(MQSession.java:3138)
at com.ibm.msg.client.wmq.v6.jms.internal.MQSession.createProducer(MQSession.java:2863)
at com.ibm.msg.client.wmq.v6.jms.internal.MQSession.createProducer(MQSession.java:2920)
at com.ibm.msg.client.jms.internal.JmsSessionImpl.createProducer(JmsSessionImpl.java:1191)
at com.ibm.msg.client.jms.internal.JmsXAQueueSessionImpl$1.createSender(JmsXAQueueSessionImpl.java:415)
at com.ibm.mq.jms.MQQueueSession.createSender(MQQueueSession.java:148)
at weblogic.deployment.jms.WrappedSession.createSender(WrappedSession.java:344)
at com.tiger.gmfs.framework.jms.QUtil.getSender(QUtil.java:216)
at com.tiger.gmfs.framework.jms.QUtil.sendMessage(QUtil.java:110)
The piece of code that i wrote is :
this is my getSender method:
protected QueueSender getSender() throws JavaMessagingException,
JMSException {
QueueSender sender = null;
queue = qsess.createQueue(qVO.getName());
sender = qsess.createSender(queue);
if (sender == null)
throw new JavaMessagingException("The queue sender is null.");
sender.setPriority(qVO.getPriority());
return sender;
}
and this is my sendMessage method:
public void sendMessage(Message jmsMessage) throws JavaMessagingException,
JMSException {
QueueSender sender = null;
try {
sender = getSender();
sender.send(jmsMessage);
} catch (JMSException j) {
Exception l = j.getLinkedException();
if (l != null) {
JavaMessagingException be = new JavaMessagingException(
"JMSErrCode:" + l + " Code:" + j.getErrorCode()
+ " Message: " + jmsMessage, j);
throw be;
} else
throw new JavaMessagingException(j);
}catch(Exception e1){
System.out.println(e1);
}finally {
if (sender != null) {
sender.close();
TracingHelper.infoLog(QUtil.class, "sendMessage",
"Closed sender");
}
}
}
What changes should i do here that my code works?
I have Implemented the same code in jre 1.7 +weblogic 12c that works perfectly but when i changed it to jre 1.6 + weblogic 11g, i get this error.

From a development point of view, when an application opens the queue - the developer has to make sure that the right open options are used to open a WebSphere MQ queue.
If the application wants to put a message, open the queue with MQOO_OUTPUT open option and not any of the MQOO_INPUT* options.
If the application wants to get a message, open the queue with any one of the below open options, but not all at the same time
MQOO_INPUT_SHARED
MQOO_INPUT_EXCLUSIVE
MQOO_INPUT_AS_Q_DEF
The reason being, if the queue being opened is an alias queue pointing to a base queue in the same queue manager where the alias queue is present, and the base queue is a local queue - both, the OUTPUT and INPUT open options are valid.
However, if the alias queue being opened is pointing to a remote queue or a topic in the same queue manager where the alias queue is present, or if the alias queue is pointing to a cluster local queue present in a different queue manager in the cluster, all of the MQOO_INPUT* open options are invalid in this scenario.
Hence it is always advisable to open a WebSphere MQ queue only and only with the appropriate open options required for the operation being performed.
In your case, if you are trying to open the alias queue with any of the MQOO_INPUT* open option, and it is pointing to a cluster local queue in a different queue manager, it is incorrect. You have to remove the MQOO_INPUT* open option from your code to resolve the issue, as the MQOO_INPUT* option is not valid in this scenario.

MQRC 2082 MQRC_UNKOWN_ALIAS_BASE_Q is telling you that the queue in question:-
MQJMS2008: failed to open MQ queue 'OFS.TIG_IND2NSE_MSG'.
is an alias queue that isn't defined correctly, because the base queue it is pointing at doesn't exist.
Suggest you use the following MQSC command to display it:-
DISPLAY QALIAS(OFS.TIG_IND2NSE_MSG) ALL
and look for the field TARGET, and then issue another MQSC command to display the queue it is aliasing:-
DISPLAY QUEUE(target-queue-name) ALL
which I expect will fail telling you the queue doesn't exist. In that case you should either define it, or correct the QALIAS definition to point at the correct target queue name.

The Problem is for an alias when the Base Queue Manager is present at the cluster or some other Remote Queue manager. setting the Queuemanger name explicitly will give this error.
if(jmsConfigQueue.getOpenOptions()!=null){
if(jmsConfigQueue.getOpenOptions().equalsIgnoreCase("Inbound"))
{
mqqueue.setBaseQueueManagerName(qcf.getQueueManager());
}
else if(jmsConfigQueue.getOpenOptions().equalsIgnoreCase("Outbound"))
{
mqqueue.setBaseQueueManagerName("");
}
else
mqqueue.setBaseQueueManagerName(qcf.getQueueManager());
}
else {
mqqueue.setBaseQueueManagerName(qcf.getQueueManager());
}
So to enable the application search the Base Queue Manager(Remote) set it as blank. as the above code.

Related

How to search for a particular message in JMS queue

I am sending some messages to a JMS queue. What are the possible ways to search for a particular message in a queue to consume?
I tried out in the following way: I am setting the JMSCorrelationID while sending a message to the queue:
public void createDQueue(String queuename, String json, Integer userid) {
try {
QueueSession.AUTO_ACKNOWLEDGE );
Queue queue = session.createQueue(queuename);
ObjectMessage objectMessage = session.createObjectMessage();
objectMessage.setJMSCorrelationID(String.valueOf(userid));
objectMessage.setObject(json);
session.createSender(queue).send(objectMessage);
session.close();
connection.close();
}catch(Exception e){
e.printStackTrace();
}
}
In the consumer code I want to get that particular message based on the JMSCorrelationID. I am not able to get that particular message. Can you suggest a solution?
public void getSpecificMessage(String queuename, Integer userid) {
try {
QueueConnectionFactory connectionFactory = new ActiveMQConnectionFactory( "tcp://localhost:61616");
((ActiveMQConnectionFactory) connectionFactory).setUseAsyncSend(true);
QueueConnection connection = connectionFactory.createQueueConnection();
connection.start();
QueueSession session = connection.createQueueSession( false,
QueueSession.AUTO_ACKNOWLEDGE );
String id = String.valueOf(userid);
Queue queue = session.createQueue(queuename);
QueueReceiver receiver = session.createReceiver(queue, "JMSCorrelationID="+id);
Message message = receiver.receive();
} catch (JMSException e) {
e.printStackTrace();
}
}
Your first problem is that you are trying to think about the message broker as a database, you must always remember this sage piece of advice, "A message broker is not a database".
There are certain limits on how deep a consumer or Queue browser can go into a destination before the broker will not page in more messages from disk, so you need to check your depth and see if its large than you maxPageSize setting and adjust as needed, but remember that messages paged in remain in memory until consumed.
Just wrap the id value in single quotes
"JMSCorrelationID='"+id+"'"
This functionality is not recommended to be used , there are lot more complications as explained by Tim , but if you want to obsolutely work with it make the change
You can search messages using the MeessageID of a message. This would be fast as messaging providers index messages on message id. There are other way to search based on CorrelationId, meta data etc.
But please remember the primary objective of using a messaging provider is to connect applications in a time independent manner. The receiving application must get messages as soon as possible. If messages are piling up in a queue, it indicates a problem that must be addressed.

DetailedJMSSecurityException while trying to access queue in IBM MQ

Here is my problem.
I am using trial version of IBM MQ V7.1. I have created a queue manager MYQM, a channel MY_SVRCONN with MCA User Id abc. I have provided user abc to access MYQM. I am trying to put a message into the queue Q1. But while getting the queue connection i am getting below exception.
com.ibm.msg.client.jms.DetailedJMSSecurityException: JMSWMQ2013: The security authentication was not valid that was supplied for QueueManager 'MYQM' with connection mode 'Client' and host name '(1500)'.
Please check if the supplied username and password are correct on the QueueManager to which you are connecting.
I have used below command to allow user abc to access MYQM.
[mqm#localhost ~]$ setmqaut -m MYQM -t qmgr -p abc +connect
The setmqaut command completed successfully.
Here is my Java program
public class MqPut
{
public static void main(String[] args)
{
sendMsg("Sample Message");
}
public static void sendMsg(String msg)
{
MQQueueConnectionFactory connectionFactory = null;
QueueConnection queueConn = null;
QueueSession queueSession = null;
QueueSender queueSender = null;
TextMessage message = null;
try
{
connectionFactory = new MQQueueConnectionFactory();
connectionFactory.setHostName(<MQ SERVER IP>);
connectionFactory.setPort(1500);
connectionFactory.setTransportType(WMQConstants.WMQ_CLIENT_NONJMS_MQ);
connectionFactory.setQueueManager("MYQM");
connectionFactory.setChannel("MY_SVRCONN");
queueConn = connectionFactory.createQueueConnection("abc","password");
queueSession = queueConn.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queueSender = queueSession.createSender(queueSession.createQueue("Q"));
queueSender.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
message = queueSession.createTextMessage(msg);
queueSender.send(message);
queueConn.close();
}
catch (Exception je)
{
je.printStackTrace();
}
}
}
I have tried with WebSphere 7, configuring JMS Q connection factory without user id: MQRC_NOT_AUTHORIZED, but still my problem persist. I am not getting what I am doing wrong. Any help is appreciated.
EDIT
User abc is not part of mqm group
Have you set chlauth (channel authentication) for the user on the svrconn channel? Channel authentication is new from MQ 7.1 onwards. The password validation is available from MQ 8 only. Basically you need to allow the remote connections from your client IP on the qmgr svrconn channel.
try in the mqsc console
SET CHLAUTH(MY_SVRCONN) TYPE(ADDRESSMAP) ADDRESS(ip of the client machine) USERSRC(CHANNEL)
If this doesnt work, check the qmgr log. It should exactly say what is causing the 2035.
A good technote is found here http://www-01.ibm.com/support/docview.wss?uid=swg21577137
Morag's really useful blog https://www.ibm.com/developerworks/community/blogs/aimsupport/entry/blocked_by_chlauth_why?lang=en
In a development environment (WMQ 8.0), I prefer to modify the authorization so that it is optional.
ALTER AUTHINFO(SYSTEM.DEFAULT.AUTHINFO.IDPWOS) AUTHTYPE(IDPWOS) CHCKCLNT(OPTIONAL)
REFRESH SECURITY TYPE(CONNAUTH)
(Disabling this feature is not recommended for production queue managers due to security implications.)
In WMQ 7.1, it's possible to set channel authorization to be disabled, but that does not appear to work on WMQ 8.0
ALTER QMGR CHLAUTH(DISABLED)
Whenever you get any error back from a queue manager, remember that you should always look in the queue manager AMQERR01.LOG for a more detailed explanation. This is especially true for any security related error, since only a single error code - MQRC_NOT_AUTHORIZED (2035) - which is translated into JMS Exception JMSWMQ2013 - is returned to the application so as to not give away the details why to any potential hacker. You must always look at the queue manager error log for the details.

Can i use RabbitMQ to move data to Amazon Kinesis stream?

I have a server containing folders date wise and each folder further contains many files (size 200kb each) containing all the log for a particular day. I am new to RabbitMQ , while going through the documentation of RabbitMQ i found below code for Producer
Refer Link: https://github.com/rabbitmq/rabbitmq-tutorials/blob/master/java/Send.java
public class Send {
private final static String QUEUE_NAME = "hello";
public static void main(String[] argv) throws Exception {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Hello World!";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes());
System.out.println(" [x] Sent '" + message + "'");
channel.close();
connection.close();
}
}
on the above code i have added sample string "Hello World!" to publish. As stated above in the problem description that i have to read the log information from the server with different date stamp directory So do i need to write a simply an infinite loop(as logs are continuously updated) and recursively read all directory and files and Then for each line of File i can compose a message and then publish it to receiver ?
In this case our channel will never close and Connection will be always up is it an idle condition with RabbitMQ ?
Is it possible for RabbitMQ to mark the file which are read and don't read it again OR i need to manage it programmatically like renaming the file and folder with some different names. I was thinking this as might be our program gets terminated with some power failure or something while i am in mid of any file and then how can i guarantee that records would not be duplicated ?
Any other best way to achieve this would be great help for me. Thanks in advance.
I would enqueue a list of files to process to RabbitMQ and then have a separate set of processes picking up messages from that queue to do what you want with the data. Then try to make sure to subscribe to the queues in ack mode, so RabbitMQ will only delete the message from the queue once you ack it. With this setting, you should prevent sending the same information twice.
That would work on most situations. I say most, because if RabbitMQ sends a message to your consumer, then your consumer takes an action (like replicating the information, or placing an entry on a database) and then the connection to RabbitMQ dies before you sent the ack to RabbitMQ, then the broker has no way of telling that you already processed the message, so it will deliver it again later.

Issues with connecting to ibm mq 7.5 using java

I'm very new to ibm mq, I find out the documents or books related to mb are so few, the only one I found is 'WebSphere MQ Using Java' written in 2004. But the real world has changed a lot.
I installed and verified mq server 7.5 on redhat linux 64 bit successfully according to this
I also created queue manager myqm1, queue LQ.TEST, channel JAVA.CHANNEL and did some test through command lines on server to ensure they work well. However when I installed a mq client on windows xp and wrote below java code, it always throw a exception:com.ibm.mq.MQException: MQJE001: Completion Code '2', Reason '2035'
my code:
import com.ibm.mq.*; import com.ibm.mq.constants.MQConstants;
/** * Simple example program */ public class MQSample {
// code identifier
static final String sccsid = "#(#) MQMBID sn=p000-L120604 su=_H-IvIK4nEeGko6IWl3MDhA pn=MQJavaSamples/wmqjava/MQSample.java";
// define the name of the QueueManager
private static final String qManager = "myqm1";
// and define the name of the Queue
private static final String qName = "LQ.TEST";
/**
* Main entry point
*
* #param args - command line arguments (ignored)
*/
public static void main(String args[]) {
try {
MQEnvironment.hostname = "58.2.221.196";
MQEnvironment.channel = "JAVA.CHANNEL";
MQEnvironment.port = 1414;
MQEnvironment.properties.put(MQC.TRANSPORT_PROPERTY, MQC.TRANSPORT_MQSERIES);
MQEnvironment.userID = "mqm";
MQEnvironment.password = "mqm";
MQEnvironment.CCSID = 1208;
// 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;
// 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);
// 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);
// Now get the message back again. First define a WebSphere MQ
// message
// to receive the data
MQMessage rcvMessage = new MQMessage();
// Specify default get message options
MQGetMessageOptions gmo = new MQGetMessageOptions();
// Get the message off the queue.
System.out.println("...and getting the message back again");
queue.get(rcvMessage, gmo);
// And display the message text...
String msgText = rcvMessage.readUTF();
System.out.println("The message is: " + msgText);
// Close the queue
System.out.println("Closing the queue");
queue.close();
// Disconnect from the QueueManager
System.out.println("Disconnecting from the Queue Manager");
qMgr.disconnect();
System.out.println("Done!");
} catch (MQException ex) {
ex.printStackTrace();
System.out.println("A WebSphere MQ Error occured : Completion Code " + ex.completionCode
+ " Reason Code " + ex.reasonCode);
} catch (java.io.IOException ex) {
System.out.println("An IOException occured whilst writing to the message buffer: " + ex);
}
return;
} }
Can anybody throw a light to me on that? I'm totally down.
To expand on Shashi's answer, since WMQ V7.1 the default CHLAUTH rules block all access on all SVRCONN channels and they block administrative access on all SVRCONN channels. If you really want to connect to JAVA.CHANNEL as mqm then you will need to override both of these behaviors.
If you are actually willing to allow remote, unauthenticated connections to the QMgr with an administrative user ID, then you have the option of disabling CHLAUTH rules altogether. You can do this by issuing the ALTER QMGR CHLAUTH(DISABLED) command in runmqsc however this is HIGHLY discouraged because it leaves the QMgr open to anonymous remote code execution using the WMQ administrative user ID. This is, however, what you appear to be trying to do.
The recommended approach would be to use an ID that is not administrative. For example, if you made an ID called mquser with a private group also called mquser then you could grant it rights to connect and inquire on the QMgr and to open the designated queue for put, get, browse and inquire. Since the ID is not administrative, it would be relatively safe to use on unauthenticated channels. You could change your code to specify the ID as mquser instead of mqm and then use a CHLAUTH rule to allow the connection. For example:
SET CHLAUTH('JAVA.CHANNEL') TYPE(USERMAP) +
CLNTUSER('mquser') USERSRC(MAP) +
MCAUSER('mquser') ACTION(ADD)
The above rule tells the QMgr "when you see a connection from the mquser ID on JAVA.CHANNEL, then set MCAUSER to mquser and allow the connection."
When you grant permissions, remember to grant them on the group and not the user. For example, if using setmqaut use the -g option and not the -p option. If there are any issues with authorization errors, you can sort these out easily using event messages. First, enable events using the ALTER QMGR AUTHOREV(ENABLED). This will cause the QMgr to emit an event message into the SYSTEM.ADMIN.QMGR.EVENT queue. You can use SupportPac MH05 or SupportPac MS0P to parse the event messages. For any given authorization event the message tells you the ID that requested access, the API call (connect, open, close etc.), the object the call was made against and the exact options that were used.
Prior to WMQ V7.1, WebSphere MQ allowed all remote connections, even anonymous, administrative ones. Although this allowed you to connect easily, in today's more hostile network environment the ability to remotely and anonymously execute code on the QMgr's host server is seen as an unacceptable security risk. So now a new QMgr is set to not allow any remote administrative access by default. As the administrator this requires you to explicitly disable security to get the old behavior or to explicitly provision secure access.
In MQ v7.5, by default access to queue manager is blocked. You need to create channel authentication records for the channel you created, JAVA.CHANNEL to allow user to access queue manager. Please follow this link for more details on Channel Authentication Records

Websphere MQ using JMS, closed connections stuck on the MQ

I have a simple JMS application deployed on OC4J under AIX server, in my application I'm listening to some queues and sending to other queues on a Websphere MQ deployed under AS400 server.
The problem is that my connections to these queues are terminated/closed when it stays idle for some time with the error MQJMS1016 (this is not the problem), and when that happens I attempt to recover the connection and it works, however, the old connection is stuck at the MQ and would not terminate until it is terminated manually.
The recovery code goes as follows:
public void recover() {
cleanup();
init();
}
public void cleanup(){
if (session != null) {
try {
session .close();
} catch (JMSException e) {
}
}
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
}
}
}
public void init(){
// typical initialization of the connection, session and queue...
}
The MQJMS1016 is an internal error and indicates that the connection loss is due to something wrong with the code or WMQ itself. Tuning the channels will help but you really need to get to the problem of why the app is spewing orphaned connections fast enough to exhaust all available channels.
The first thing I'd want to do is check the versions of WMQ and of the WMQ client that are running. If this is new development, be sure you are using the WMQ v7 client because v6 is end-of-life as of Sept 2011. The v7 client works with v6 QMgrs until you are able to upgrade that as well. Once you get to v7 client and QMgr, there are quite a bit of channel tuning and reconnection options available to you.
The WMQ v7 client download is here: http://bit.ly/bXM0q3
Also, note that the reconnect logic in the code above does not sleep between attempts. If a client throws connection requests at a high rate of speed, it can overload the WMQ listener and execute a very effective DOS attack. Recommended to sleep a few seconds between attempts.
Finally, please, PLEASE print the linked exceptions in your JMSException catch blocks. If you have a problem with a JMS transport provider, the JMS Linked Exception will contain any low-level error info. In the case of WMQ it contains the Reason Code such as 2035 MQRC_AUTHORIZATION_ERROR or 2033 MQRC_NO_MSG_AVAILABLE. Here's an example:
try {
.
. code that might throw a JMSException
.
} catch (JMSException je) {
System.err.println("caught "+je);
Exception e = je.getLinkedException();
if (e != null) {
System.err.println("linked exception: "+e);
} else {
System.err.println("No linked exception found.");
}
}
If you get an error at 2am some night, your WMQ administrator will thank you for the linked exceptions.
Since the orphaned connections (stuck connections on MQ side) does not affect the messages processing (i.e. they do not consume messages), we left things as it is until the maximum connections allowed on the MQ was reached.
The recovery did not work anymore, and once we reached that point, the MQ administrator had to clean the orphaned connection manually, however, the good news is that searching for this particular problem led to an issue reported on IBM support site:
check here

Categories