How to force delete Queue on Qmanager with PCF commands - ibm-mq

Currently I use PCF command to delete a Queue on QMANAGER with
PCFMessage message = new PCFMessage( CMQCFC.MQCMD_DELETE_Q );
message.addParameter( CMQC.MQCA_Q_NAME, name);
agent.send( message );
Could I force delete if queue is occupied?
I have tried without succes on QL
#Override
protected PCFMessage getRequestRemove(String objetName,
String qmanagerName,boolean forceQmanager) {
PCFMessage request = new PCFMessage(CMQCFC.MQCMD_DELETE_Q);
request.addParameter( CMQCFC.MQIACF_PURGE, CMQCFC.MQPO_YES );
request.addParameter(CMQC.MQCA_Q_NAME, objetName);
request.addParameter(CMQC.MQIA_Q_TYPE, CMQC.MQQT_LOCAL);
return request;
}
Error code is Caused by: com.ibm.mq.pcf.PCFException: MQJE001: Code achèvement '2', Motif '3014'.
My PCF library is 7.1.0.4
regards

There is no FORCE option on a DELETE queue command. If the queue is currently open by an application for input and they are waiting in an MQGET you can kick them out with the following command.
MQSC
ALTER QLOCAL(q-name) GET(DISABLED)
PCF
PCFMessage message = new PCFMessage (CMQCFC.MQCMD_CHANGE_Q);
message.addParameter(CMQC.MQCA_Q_NAME, name);
message.addParameter(CMQC.MQIA_INHIBIT_GET, CMQC.MQQA_GET_INHIBITED);
agent.send(message);
However if the queue is currently open and the application is not currently in either an MQGET or an MQPUT, then you cannot kick them out in this way, your only option then is to find the application in question using DISPLAY CONN, and then issue a STOP CONN to get them to release the queue.
The mostly likely occupation of a queue is the long MQGET-waiter, and so the above example command will help for most cases.

Morag's answer addresses possible ways to disconnect processes that currently have the queue open, if you also want to remove the queue when messages are on the queue you would need to ask MQ to PURGE the messages:
PCFMessage message = new PCFMessage( CMQCFC.MQCMD_DELETE_Q );
message.addParameter( CMQC.MQCA_Q_NAME, name);
message.addParameter( CMQCFC.MQIACF_PURGE, CMQCFC.MQPO_YES );
agent.send( message );

Related

How to consume message from RabbitMQ dead letter queue one by one

The requirement is like to process the messages from dead letter queue by exposed a REST service API(Spring Boot).
So that once REST service is called, one message will be consumed from the DL queue and will publish in the main queue again for processing.
#RabbitListener(queues = "QUEUE_NAME") consumes the message immediately which is not required as per the scenario. The message only has to be consumed by the REST service API.
Any suggestion or solution?
I do not think RabbitListener will help here.
However you could implement this behaviour manually.
Spring Boot automatically creates RabbitMq connection factory so you could use it. When http call is made just read single message from the queue manually, you could use basic.get to synchronously get just one message:
#Autowire
private ConnectionFactory factory
void readSingleMessage() {
Connection connection = null;
Channel channel = null;
try {
connection = factory.newConnection();
channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
GetResponse response = channel.basicGet(QUEUE_NAME, true);
if (response != null) {
//Do something with the message
}
} finally {
//Check if not null
channel.close();
connection.close();
}
}
If you are using Spring; you can avoid all the boilerplate in the other answer using RabbitTemplate.receive(...).
EDIT
To manually ack/reject the message, use the execute method instead.
template.execute(channel -> {
GetResponse got = channel.basicGet("foo", false);
// ...
channel.basicAck(got.getEnvelope().getDeliveryTag(), false);
return null;
});
It's a bit lower level, but again, most of the boilerplate is taken care of for you.

JMS and IBM WebSphere not generating COD

I am creating an application that consumes messages from a MQ using JMS. My MQ manager is IBM WebSphere MQ and I am using the IBM jms implementation to consume the messages.
The messasges are coming and going fine. I receive the messages from the other part and I can send messages to them. The problem is that they are not receiving the COD after I consume the message from the queue. They receive the COA, but no COD.
Here is my receive message code:
public byte[] readMsgFromClient() throws JMSException {
byte[] message = null;
QueueReceiver reader = null;
try {
connection = getQueueConnection();
connection.start();
session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue(config.getQueueRsp());
((MQQueue) queue).setTargetClient(JMSC.MQJMS_CLIENT_NONJMS_MQ);
reader = session.createReceiver(queue);
JMSBytesMessage byteMessage = (JMSBytesMessage) reader.receive(3000);
if (byteMessage != null) {
message = new byte[(int) byteMessage.getBodyLength()];
byteMessage.readBytes(message);
}
} finally {
if (reader != null) {
reader.close();
}
if (session != null) {
session.close();
}
if (connection != null) {
connection.close();
}
}
return message;
}
Do I have to manually send the COD? DO I have to configure my WebSphere to automatically send the COD? Do I have to notify the WebSphere that my application has consumed the message?
The COD messages are probably ending up the the dead letter queue (DLQ) with an RC (Reason Code) of 2035 (not authorized).
Here is another of those things you learn the hard way:
COA messages are generated under the queue manager's UserId
COD messages are generated under the UserId of the sender's message.
If the sending application's UserId is appl001 then the COD will be generated using the UserId of appl001. If that UserId does not have permission to write to the particular queue then the message will end up in the DLQ.
Generally, the permission issue happens when the sender application is connected to 1 queue manager and the receiver application is connected to another queue manager. i.e. messages are hoping between queue managers.
Hence, the sender's UserId does not have permission to put a message on the remote queue manager.
As stated by #Roger, the permissions to put the COD are based on the UserId in the MQMD of the message that is sent.
If you do not want to add the remote user to your local system you can use the itsoME exit provided in the IBM Redbook "Secure Messaging Scenarios with WebSphere MQ". The latest version is found under the "Additional Material" link.
With this exit you need to have a MCAUSER set on your RCVR or RQSTR channel and configure that channel with the following attributes:
MSGEXIT('itsoME(MsgExit)')
MSGDATA('MCA/')
The result is that UserIdentifier field of the MQMD will be changed to the value of the MCAUSER that is configured on the channel. You would then give that MCAUSER +put and +passid to the XMITQ that returns to the remote queue manager.
The exit can be used for other things such as removing the reporting options if you do not want to allow COA/COD.

Receive method in JMS waiting for messages

I want a method to browse all messages from a messsage queue and can send it to another queue using jmstemplate with using Websphere queues(NOT MQ). I have tried using receive and it is able to retrieve all the messages from the queue but it is still waiting for another message. And the messages are being lost. It must be in a transaction
The Code I have Tried:
**String message = (String) jmsTemplate.receiveAndConvert();
System.out.print(message);
while ((message = (String) jmsTemplate.receiveAndConvert()) != null) {
messages.add(message);
}
return messages;
}**
The JMStemplate should be used for only synchronous read or sending message. For asychronous read use one of the listener implementation. Read here

MQQueueManager: What to expect from isConnected state after creation, during use?

I inherited this lovely bit of code below.
The way I read it the developer makes three assumptions:
An MQQueueManager instance is not necessarily created in a state where isConnected() returns true
If it is created in state isConnected() == false, the state might change "later", hence the timeout code
If you try to create an access queue from a disconnected MQQueueManager, it will not throw an exception.
What I would expect is that an MQQueueManager instance is created in state isConnected() == true, that this state might change later (network failure etc), and that this state change (isConnected() == false) would cause an operation on the queue to fail with an MQException.
The documentation is delightfully silent on these points, except to note that the only way to reconnect to a queue after manually disconnecting the MQQueueManager is to create a new instance of MQQueueManager.
Who can set me straight here?
qMgr = new MQQueueManager( qManager );
// Set up the options on the queue we wish to open...
// Note. All WebSphere MQ Options are prefixed with MQC in Java.
final int openOptions = MQC.MQOO_INPUT_AS_Q_DEF | MQC.MQOO_OUTPUT;
// Now specify the queue that we wish to open,
// and the open options...
queue = qMgr.accessQueue( queueName, openOptions );
// Set the get message options...
final MQGetMessageOptions gmo = new MQGetMessageOptions(); // accept the
// defaults
gmo.options = MQC.MQGMO_WAIT;
gmo.waitInterval = 1000;
connectionStatus = CONNECTING;
int timeOutCounter = 0;
while(!qMgr.isConnected()) {
InboundMsgTask.sleep(1000);
timeOutCounter++;
if(timeOutCounter > 4) {
connectionStatus = TIME_OUT;
return;
}
}
connectionStatus = CONNECTED;
Instead of checking the IsConnected==True, it is better to go ahead make the actual MQ .NET method call (Get, Put etc). If the connection is broken these calls would throw a connection broken execption (MQRC 2009). Remember the IsConnected could be True before a MQ method is called but it can change during the execution of a MQ method. Your code needs to handle the connection broken exception and call the MQQueueManager.Disconnect method and then re-establish the connection. The Disconnect call would free up any resources allocated and close all gracefully any queue manager objects that were opened. Ignore any exception thrown by the Disconnect method.
If you are using MQ v7.1 or v7.5, then the .NET client can automatically reconnect to queue manager if it detects connection errors. You will need to enable the automatic reconnect option. Please see the MQ InfoCenter.
EDIT:
A new MQQueueManager() will return an instance of MQQueueManager class if connection to queue manager is successfully established. In case of errors, a MQExceptionwill be thrown. There is no need to wait for connection to complete as MQQueueManager constructor is a blocking call.

Getting the Queue name from within the MDB

I have 2 Websphere application Server(WAS) applications, one sending a message and the other reading and processing it . I need the queue name to be known in the reading application for my downstream processing.
I am trying to get the queue name (in the reading application) by using the following code . But however I get NullPointerException since the getJMSDestination is returning null.
Queue queue = (Queue)message.getJMSDestination();
logger.info("Queue ID: "+queue.getQueueName());
Note that the queue name is set via the destination object in the sending application.
Is there any other parameters that I am missing to set in the sending application ?
The message should have the destination stored in its JMSDestination property, you can try fetch that instead of using getJMSDestination()
I've using Spring with ActiveMQ, and this appears to work for me:
public void processMessage( Message msg )
{
// Get the queue name from the supplied Message.
String sourceQueueName = "UNKNOWN";
try
{
ActiveMQDestination sourceQueue = (ActiveMQDestination) msg.getJMSDestination();
sourceQueueName = sourceQueue.getPhysicalName();
}
catch ( JMSException e )
{
LOGGER.error( "Cannot get JMSDestination from Message: " + msg, e );
}
....
Does WAS have a Queue object you can cast to that exposes similar methods?

Resources