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.
Related
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.
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 );
I am using jpos client (In one of the class of java Spring MVC Program) to connect the ISO8585 based server, however due to some reason server is not able to respond back, due to which my program keeps waiting for the response and results in hanging my program. So what is the proper way to implement connection timeout?
My client program look like this:
public FieldsModal sendFundTransfer(FieldsModal field){
try {
JposLogger logger = new JposLogger(ISO_LOG_LOCATION);
org.jpos.iso.ISOPackager customPackager = new GenericPackager(ISO_PACKAGER);
ISOChannel channel = new PostChannel(ISO_SERVER_IP, Integer.parseInt(ISO_SERVER_PORT), customPackager);// live
logger.jposlogconfig(channel);
channel.connect();
log4j.info("Connection established using PostChannel");
ISOMsg m = new ISOMsg();
m.set(0, field.getMti());
//m.set(2, field.getField2());
m.set(3, field.getField3());
m.set(4, field.getField4());
m.set(11, field.getField11());
m.set(12, field.getField12());
m.set(17, field.getField17());
m.set(24, field.getField24());
m.set(32, field.getField32());
m.set(34, field.getField34());
m.set(41, field.getField41());
m.set(43, field.getField43());
m.set(46, field.getField46());
m.set(49, field.getField49());
m.set(102,field.getField102());
m.set(103,field.getField103());
m.set(123, field.getField123());
m.set(125, field.getField125());
m.set(126, field.getField126());
m.set(127, field.getField127());
m.setPackager(customPackager);
System.out.println(ISOUtil.hexdump(m.pack()));
channel.send(m);
log4j.info("Message has been send");
ISOMsg r = channel.receive();
r.setPackager(customPackager);
System.out.println(ISOUtil.hexdump(r.pack()));
channel.disconnect();
}catch (Exception err) {
System.out.println("sendFundTransfer : " + err);
}
return field;
}
Well the real proper way would be to use Q2. Given you don't need a persistent connection you coud just set a timeout for the channel.
PostChannel channel = new PostChannel(ISO_SERVER_IP, Integer.parseInt(ISO_SERVER_PORT), customPackager);// live
channel.setTimeout(timeout); //timeout in millies.
This way channel will autodisconnect if nothing happens during the time specified by timeout , and your call to receive will throw an exception.
The alternative is using Q2 and a mux (see QMUX, for which you need to run Q2, or ISOMUX which is kind of deprecated).
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.
In my .net 2.0 application Remote object suddenly destroyed and thrown the below exception.
"Failed to connect to an IPC Port: The system cannot find the file specified."
I have IPC remoting server and which create a singleton object.
i have override the InitializeLifetimeService() method and returns null for infinite lifetime.
server and client applications are working fine but some times we got the above exception.
serverCode:
//create and register the processheartbeat.
BinaryServerFormatterSinkProvider serverprovider = new BinaryServerFormatterSinkProvider();
serverprovider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
//Hosts the Heartbeat object and registers it.
processHeartbeatChn = new IpcServerChannel("HeartbeatChannel", "localhost:" + applicationHeartbeatPort, serverprovider);
//registers the channel
ChannelServices.RegisterChannel(processHeartbeatChn, false);
//register the service
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Heartbeat),
appName, WellKnownObjectMode.Singleton);
ClientCode:
string uri = string.Format(CultureInfo.InvariantCulture,"ipc://localhost:{0}/{1}", applicationHeartbeatPort, appName);
//get the Heartbeat object
remoteHeartbeat = (Heartbeat)Activator.GetObject(typeof(Heartbeat), uri);
any hot fix is there to resolve this problem?
can any one help me an this?