MQQueue get call fails to get the message from queue - ibm-mq

MQQueue get call fails to retrieve the message from the queue with 2033 (07F1) (RC2033): MQRC_NO_MSG_AVAILABLE error. I am using the following code to get the message from the queue:
GET message:
byte[] replyMessageBytes = null;
try {
this.replyConnection.open();
MQQueue replyQueue = this.replyConnection.getQueue(CMQC.MQOO_INPUT_AS_Q_DEF);
if (null == replyQueue) {
logger.error("Could not create reply queue.");
throw new PFMCommunicationException("Could not create reply queue.");
}
MQMessage replyMessage = new MQMessage();
MQGetMessageOptions gmo = new MQGetMessageOptions();
gmo.resolvedQueueName = replyQueue.getResolvedQName();
if (timeout.length > 0) {
try {
gmo.waitInterval = Integer.valueOf("" + timeout[0]);
} catch (NumberFormatException e) {
}
} else {
gmo.waitInterval = MQConstants.MQWI_UNLIMITED;
}
gmo.options = MQConstants.MQGMO_WAIT;
if (null != correlationId) {
gmo.matchOptions = MQConstants.MQMO_MATCH_MSG_ID | MQConstants.MQMO_MATCH_CORREL_ID;
replyMessage.messageId = correlationId.getBytes();
replyMessage.correlationId = correlationId.getBytes();
} else {
gmo.matchOptions = MQConstants.MQMO_NONE;
replyMessage.messageId = MQConstants.MQMI_NONE;
replyMessage.correlationId = MQConstants.MQCI_NONE;
}
try {
replyQueue.get(replyMessage, gmo);
int length = replyMessage.getMessageLength();
replyMessageBytes = replyMessage.readStringOfByteLength(length).getBytes();
} catch (MQException e) {
logger.error("ERROR on receiving reply: CC=" + e.completionCode + " RC=" + e.reasonCode + " "
+ e.getMessage());
} catch (IOException e) {
logger.error("ERROR on receiving reply.", e);
}
if (null == replyMessageBytes) {
logger.error("No reply received.");
} else {
logger.debug("Received message: " + new String(replyMessageBytes));
}
} catch (MQException e) {
logger.error("ERROR:", e);
throw new PFMCommunicationException(e);
} catch (PFMConnectionException e) {
logger.error(e.getMessage());
throw new PFMCommunicationException(e);
} finally {
this.replyConnection.close();
logger.debug("Closed connection with MQ replies.");
}
I confirm that the message is present in the queue before the waitInterval expires and the correlationId also matches. In-fact, when I run the code without trying to match the correlationId, I am able to get the message. I guess this means either something is wrong with the response message or I am making a mistake creating the matchOptions properly.
gmo.matchOptions = MQConstants.MQMO_NONE;
replyMessage.messageId = MQConstants.MQMI_NONE;
replyMessage.correlationId = MQConstants.MQCI_NONE;
This is what my response message header looks like:
<Header Origin="DISPUTE1" Addressee="PSXDX2" Date="20180802" Time="123055" Area="QUERY" Content="RAddr" ID="8af3257cf01a4842bf5eec8d" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="cms/customerAccountDetails.xsd">
I tried with putting CorrelId instead of ID in the response header but it's still the same. Can someone please help me to find the issue?

if (null != correlationId) {
gmo.matchOptions = MQConstants.MQMO_MATCH_MSG_ID | MQConstants.MQMO_MATCH_CORREL_ID;
replyMessage.messageId = correlationId.getBytes();
replyMessage.correlationId = correlationId.getBytes();
}
Well, that's your problem. It would be extremely rare, if ever, that an MQ message would have the same value in BOTH the MsgId and CorrelId fields.
If you are getting a reply message for a request that you sent, and you saved the request message's MsgId after the MQPUT, then the code should be:
if (null != correlationId) {
gmo.matchOptions = MQConstants.MQMO_MATCH_CORREL_ID;
replyMessage.correlationId = correlationId.getBytes();
}
Note: You don't save the request (outbound) message's CorrelId but rather the MsgId. The server processing your request, should put the incoming MsgId in the reply message's CorrelId. Hence, that is why you ONLY match on CorrelId for the reply message.

Related

Unable to get original string message send from third party system

When getting message from third part system using MQ, it is displaying like bytes array instead of original string sent by third party system.
For example:
Original Json String sent bt third part system {"name":"sonoo","salary":600000.0,"age":27}
Received String from MQ is : 123,34,82,101,103,68,101,99,77,115,103,34,58,123,34,72,100,114,34,58,123,34,64,84,109,79,102,102,34,58,34,43,48,56,58,48,48,34,44,34,64,68,116,109,34,58,34,50,48,50,51,45,48,49,45,49,56
Expected result: {"name":"sonoo","salary":600000.0,"age":27}
#GenerateTransactionID
#JmsListener(destination = "${mq.queueName}", containerFactory = "${mq.containerFactory}", concurrency = "${mq.receiver.concurrency}")
public void receiveMessage(String jsonString) {
try
{
logger.debug(" Message received from third party::: " +jsonString);
if(jsonString.contains("RegDecMsg") && jsonString.contains("DocId")) {
Map<String, Object> jsonMap = dmgJsonParser.parseAsTree(jsonString);
StringBuilder sb = new StringBuilder();
printMapForDebugging(jsonMap, sb, jsonString);
logger.debug(" Attributes \n {}" +sb);
dmgJsonTraverser.processJsonNodes(jsonMap);
} else {
logger.debug(" Received message from third party is not in the expected format::: " +jsonString);
}
} catch (NullPointerException nx) {
logger.error(" Error while processing message:: "+ jsonString, " Please contact support!! ", nx);
} catch (Exception ex) {
logger.error(" Error while processing message:: "+ jsonString, " Please contact support!! ", ex);
throw ex;
}
}

SSE server sending events in a batch on final close

I have a Jersey server running locally, it exposes a SSE resource just like the examples here: https://jersey.github.io/documentation/latest/sse.html. I have a local webpack Angular app, that binds to the exposed GET endpoint and listens for data.
On the GET, I start up a thread to send notifications at regular intervals over 6-8 seconds. I don't see anything on the client UNTIL the EventOutput object is closed.
What am I doing wrong, and how can I fix this?
The server code WORKS with just a simple curl, i.e.:
curl http://localhost:8002/api/v1/notify
But on both Chrome and Safari the following code exhibits the behavior
Client (TypeScript):
this.evSource = new EventSource('http://localhost:8002/api/v1/notify');
this.evSource.addEventListener(
'event',
(x => console.log('we have ', x))
);
this.evSource.onmessage = (data => console.log(data));
this.evSource.onopen = (data => console.log(data));
this.evSource.onerror = (data => {
console.log(data);
this.evSource.close();
});
Server (Java):
// cache callback
public void eventCallback(Iterable<CacheEntryEvent<? extends Integer, ? extends Integer>> events) {
for (CacheEntryEvent<? extends Integer, ? extends Integer> x : events) {
LOGGER.info("{} Sending the following value: " + x.getValue(), Thread.currentThread().getId());
final OutboundEvent sseEvent = new OutboundEvent.Builder().name("event")
.data(Integer.class, x.getValue()).build();
this.broadcaster.broadcast(sseEvent);
}
}
#GET
#Produces(SseFeature.SERVER_SENT_EVENTS)
#ApiOperation(value = "Setup SSE pipeline", notes = "Sets up the notification pipeline for clients to access")
#ApiResponses(value = {
#ApiResponse(code = HttpURLConnection.HTTP_UNAUTHORIZED,
message = "Missing, bad or untrusted cookie"),
#ApiResponse(code = HttpURLConnection.HTTP_OK,
message = "Events streamed successfully")
})
#Timed
#ResponseMetered
public EventOutput registerNotificationEvents(
#HeaderParam(SseFeature.LAST_EVENT_ID_HEADER) String lastEventId,
#QueryParam(SseFeature.LAST_EVENT_ID_HEADER) String lastEventIdQuery) {
if (!Strings.isNullOrEmpty(lastEventId) || !Strings.isNullOrEmpty(lastEventIdQuery)) {
LOGGER.info("Found Last-Event-ID header: {}", !Strings.isNullOrEmpty(lastEventId) ? lastEventId : lastEventIdQuery );
}
LOGGER.info("{} Received request", Thread.currentThread().getId());
this.continuation = true;
final EventOutput output = new EventOutput();
broadcaster.add(output);
Random rand = new Random();
IntStream rndStream = IntStream.generate(() -> rand.nextInt(90));
List<Integer> lottery = rndStream.limit(15).boxed().collect(Collectors.toList());
IgniteCache<Integer, Integer> cache = this.ignite.cache(topic_name);
executorService.execute(() -> {
try {
lottery.forEach(value -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
LOGGER.info("{} Sending the following value to Ignite: " + value + " : " + count++, Thread.currentThread().getId());
if (!cache.isClosed()) {
cache.put(1, value);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
TimeUnit.MILLISECONDS.sleep(500);
continuation = false;
TimeUnit.MILLISECONDS.sleep(500);
if (!output.isClosed()) {
// THIS is where the client sees ALL the data broadcast
// in one shot
output.close();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
});
LOGGER.info("{} Completing request", Thread.currentThread().getId());
return output;
}
}
Looks like http://github.com/dropwizard/dropwizard/issues/1673 captures the problem. GZip default won't flush even if upper levels ask for it. Solution is something like
((AbstractServerFactory)configuration.getServerFactory()).getGzipFilterFactory().setSyncFlush(true);
will enable flushing to synchronize with GZip if disabling GZip all up is not an option

Android Asynctask return problems

I am facing a problem in value 'return' in Asynctask class in doInBackground method. I am getting an error, about 'missing return statement in below code.
`public class ForecastNetwork extends AsyncTask {
public final String TAG = ForecastNetwork.class.getSimpleName();
#Override
protected Void doInBackground(Void... params) {
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page, at
// http://openweathermap.org/API#forecast
URL url = new URL("http://api.openweathermap.org/data/2.5/forecast/daily?q=94043&mode=json&units=metric&cnt=7");
// Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
// Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
// Nothing to do.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
// Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
// But it does make debugging a *lot* easier if you print out the completed
// buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = buffer.toString();
} catch (IOException e) {
Log.e(TAG, "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(TAG, "Error closing stream", e);
}
}
}
}`
What Should I return at the end?
I assume that you forgot to return the processing result
forecastJsonStr = buffer.toString();
return forecastJsonStr;

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());

SNMP4J adding user

I've been doing some very basic SNMP4J programming. All I want to do is send a simple "get" request but so far my responses have been null. I opened up wireshark and found that in the under Simple Network Management Protocol, my msgUserName is blank and I need that to be populated.
I thought I had set it using the following code:
Snmp snmp = new Snmp(transport);
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);
transport.listen();
UsmUser user = new UsmUser(new OctetString("SNMPManager"), AuthSHA.ID,new OctetString("password"),null,null);
// add user to the USM
snmp.getUSM().addUser(user.getSecurityName(), user);
Am I going about it the wrong way? If not, how do I set the msgUserName as seen in my wireshark dump of the get-request? I'm very new to SNMP, so I'm essentially running off examples.
This is a working snmpset you can write snmp get same way.Snmp4j v2 and v3 not using same api classes.
private void snmpSetV3(VariableBinding[] bindings) throws TimeOutException, OperationFailed {
Snmp snmp = null;
try {
PDU pdu = new ScopedPDU();
USM usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
SecurityModels.getInstance().addSecurityModel(usm);
snmp = new Snmp(new DefaultUdpTransportMapping());
snmp.getUSM().addUser(new OctetString(Username), new UsmUser(new OctetString(Username), AuthMD5.ID, new OctetString(Password), AuthMD5.ID, null));
ScopedPDU scopedPDU = (ScopedPDU) pdu;
scopedPDU.setType(PDU.SET);
scopedPDU.addAll(bindings);
UserTarget target = new UserTarget();
target.setAddress(new UdpAddress(IPAddress + "/" + Port));
target.setVersion(version); //SnmpConstants.version3
target.setRetries(retries);
target.setTimeout(timeout);
target.setSecurityLevel(securityLevel); //SecurityLevel.AUTH_NOPRIV
target.setSecurityName(new OctetString(Username));
snmp.listen();
ResponseEvent response = snmp.send(pdu, target);
if (response.getResponse() != null) {
PDU responsePDU = response.getResponse();
if (responsePDU != null) {
if (responsePDU.getErrorStatus() == PDU.noError) {
return;
}
throw new OperationFailed("Error: Request Failed, "
+ "Error Status = " + responsePDU.getErrorStatus()
+ ", Error Index = " + responsePDU.getErrorIndex()
+ ", Error Status Text = " + responsePDU.getErrorStatusText());
}
}
throw new TimeOutException("Error: Agent Timeout... ");
} catch (IOException e) {
throw new OperationFailed(e.getMessage(), e);
} finally {
if (snmp != null) {
try {
snmp.close();
} catch (IOException ex) {
_logger.error(ex.getMessage(), ex);
}
}
}
}

Resources