Get the Correlation ID from MQ as string - java

I am setting the Correlation ID while sending the message to MQ. And I need to use the CorrelationID from the COA of the message I pushed for the further processing.
I am setting the correlation ID and sending the message to queue using the below code.
MQMessage message = createMQMessage("12345");
message.write("Some message to push".getBytes());
queue.put(message);
private MQMessage createMQMessage(String corrID){
MQMessage message = new MQMessage();
message.messageFlags = MQConstants.MQMF_SEGMENTATION_ALLOWED;
if (ackQueueName != null) {
message.messageType = MQConstants.MQMT_REQUEST;
message.replyToQueueManagerName = ackQueueManagerName;
message.replyToQueueName = ackQueueName;
message.report = MQConstants.MQRO_COA | MQConstants.MQRO_COD;
message.correlationId = corrID.getBytes();
}
return message;
}
I am reading the replyQueue from another application to get the COA and extract the correlation ID for further processing.
But the correlation ID is in byte[] format and I used the below method getHexString to get the string. But all I got is 48 digit Hex format of my correlation ID like
414d5120514d41444556202020202020b5ca0d5b13b3bb20
public static String getHexString(byte[] b) throws Exception {
String result = "";
for (int i=0; i < b.length; i++) {
result += Integer.toString( ( b[i] & 0xff ) + 0x100, 16).substring( 1 );
}
return result;
}
All I need is the approach to convert the 48digit HexString to the Original Correlation ID I set. I tried using the below method to convert, but its giving me the junk data.
public static String hexStringToByteArray(String hex) {
int l = hex.length();
byte[] data = new byte[l/2];
for (int i = 0; i < l; i += 2) {
data[i/2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
+ Character.digit(hex.charAt(i+1), 16));
}
return new String(data);
}

Your report options are not explicitly set.
MQRO_COPY_MSG_ID_TO_CORREL_ID This is the default action, and
indicates that if a report or reply is generated as a result of this
message, the MsgId of this message is copied to the CorrelId of the
report or reply message.
Because of the default action, you will never receive the initial Correlation ID of your message. As Roger mentioned in his answer, it is bad practice to set the MsgID programmatically. Simply use the following option to have the CorrelID copied to the report message:
MQRO_PASS_CORREL_ID If a report or reply is generated as a result of
this message, the CorrelId of this message is copied to the CorrelId
of the report or reply message.
message.report = MQConstants.MQRO_COA
| MQConstants.MQRO_COD
| MQConstants.MQRO_PASS_CORREL_ID;

I set the message ID myself, now I am getting it fine
Do NOT set the message's messageId yourself. Let the queue manager create a unique messageId for each message that is put to a queue. If you need to pass information along with the message either (1) put it in the message data/payload or (2) add a Message Property (aka Named Property) to the message.
If you create your own messageId then there is a chance of duplicate messageIds which is a very bad thing and goes against Best Practices. IBM MQ Best Practices says to let the queue manager create a unique messageId.

Related

SNMP Listener can not read trap from OIDs that are entries in a table

I have written a SNMP listener in Java using the TNM4J library which uses the SNMP4J library.
The listener is able to read received traps, except for traps that appear to be indexed in a table.
The listener is listening to traps from an Ericsson object, which means I am using the ERICSSON-ALARM-MIB and the MIB imports it needs. The trap I am receiving is the eriAlarmActiveManagedObject with OID .1.3.6.1.4.1.193.183.4.1.3.5.1.5, but I also tested it locally with the other traps in the table and the same error occurs
If one looks at https://mibs.observium.org/mib/ERICSSON-ALARM-MIB/ :
All the traps that are from a table like this can not be read by the listener.
It gives an index out of bound exception from a extractIndexes method in MibbleIndexExtractor.java in the TNM4J library.
#Override
public IndexDescriptor[] extractIndexes(String instanceOid) {
String oid = symbol.getValue().toString();
String suboid = instanceOid.substring(oid.length() + 1);
int[] components = oidToArray(suboid);
int offset = 0;
IndexDescriptor[] descriptors = new IndexDescriptor[indexes.length];
for (int i = 0; i < indexes.length; i++) {
SnmpIndex index = indexes[i];
MibValueSymbol indexSymbol = symbol.getMib().getSymbolByOid(index.getValue().toString());
MibType indexType = ((SnmpObjectType) indexSymbol.getType()).getSyntax();
int length = fixedLength(indexType);
boolean implied = length != -1 || index.isImplied();
if (length == -1) {
length = variableLength(indexType, components, offset, index.isImplied());
}
int[] encoded = new int[length];
System.arraycopy(components, offset, encoded, 0, length);
descriptors[i] = new MibbleIndexDescriptor(indexSymbol, encoded, implied);
offset += length;
}
return descriptors;
}
I have debugged it and this happens because the oid String and instanceOid String are identical which of course causes an exception where the suboid String is being created.
However on all other traps it never calls this extractIndexes method, but just works finely and prints out the trap and oid name correctly.
Any suggestion on how to fix this issue?
After being in contact with the developer of TNM4J he made some fixes to his library.
After that the Ericsson oids was being correctly translated. There was a few missing translations from oids, which was because of the loading order of the MIBs.
Re-adjusting these made it work.
For anyone interested the troubleshooting process with the developer can view it here:
https://github.com/soulwing/tnm4j/issues/9

How to set message Id for IBM MQ using java program

I am able to set correlation id for IBM mq but unable to set message id for the message the message id I am setting is being overridden by the MQ how to set this message id below one is the code I am trying please help me on this task. Is there any thing I need do in the code???
public static void main(String args[])
{
try{
MQQueueConnectionFactory cf = new MQQueueConnectionFactory();
cf.setHostName("xxx");
cf.setPort(4444);
cf.setTransportType(1);
cf.setQueueManager("xxxx");
cf.setChannel("CLIENT.xyZ");
MQQueueConnection connection = (MQQueueConnection) cf.createQueueConnection();
MQQueueSession session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
MQQueue queue = (MQQueue) session.createQueue("WW.ESB.ENTRY.SERVICE.IN");
queue.setBooleanProperty(WMQConstants.WMQ_MQMD_WRITE_ENABLED, true);
queue.setIntProperty(WMQConstants.WMQ_MQMD_MESSAGE_CONTEXT, WMQConstants.WMQ_MDCTX_SET_IDENTITY_CONTEXT);
MQQueueSender sender = (MQQueueSender) session.createSender(queue);
true);
File f=new File("C:/InputPayloads/Payloads/test4.xml");
JMSTextMessage message = (JMSTextMessage) session.createTextMessage(FileUtils.readFileToString(f));
message.setStringProperty("JMS_IBM_MQMD_UserIdentifier", "avada2");
// Hex-string 010203040506070801020304050607080102030405060708
byte[] customMessageId = new byte[24];
for (int i = 0; i < 24; i++) {
customMessageId[i] = (byte) ((i % 8) + 1);
}
message.setObjectProperty(WMQConstants.JMS_IBM_MQMD_MSGID, customMessageId);
message.setStringProperty("xxx", "SH_TEST04");
message.setStringProperty("yyy", "JP");
message.setStringProperty("zzz", "1");
connection.start();
System.out.println("before Sent message:\\n" + message);
sender.send(message);
System.out.println("Sent message:\\n" + message);
sender.close();
session.close();
connection.close();
}catch(Exception e)
{
System.out.println(e);
}
}
}
I am getting below error
com.ibm.msg.client.jms.DetailedJMSSecurityException: JMSWMQ2008: Failed to open MQ queue 'WW.zzz.xxx.yyy.zz'.
JMS attempted to perform an MQOPEN, but IBM MQ reported an error.
Use the linked exception to determine the cause of this error. Check that the specified queue and queue manager are defined correctly.
due to this line
The JMS Spec indicates that the message ID must be set by the JMS provider and that it must either be unique or null, i.e. you can't set it yourself.
However, you can use an IBM MQ specific extension to set the Message ID yourself, bearing in mind that you are now breaking the JMS Spec.
To do so, you need to set JMS_IBM_MQMD_MsgId, whose value is then copied into JMSMessageID (i.e. you can't set it directly).
Now you know the name of the attribute to set, see this other question for more details and a code example in an answer from an IBM MQ JMS expert (#Calanais).
Further reading
JMS message object properties
Reading and writing the message descriptor from a WebSphere MQ classes for JMS application

SMPP Server CloudHopper - how I should receive multipart messages?

I have CloudHopper SMPP server, at this moment I can receive a simple short messages.
if (pduRequest.getCommandId() == SmppConstants.CMD_ID_SUBMIT_SM) {
SubmitSm request = (SubmitSm) pduRequest;
request.getShortMessage();
....
}
But what I should do to receive long (Multipart) message?
I don't know what object I have to use ...
Help me, please.
Many thanks.
The following processes a multipart long message PDU that you would get when receiving a long message that has been split into multiple PDUs:
import com.cloudhopper.commons.charset.GSMCharset;
import com.cloudhopper.commons.gsm.GsmUtil;
import com.cloudhopper.smpp.pdu.DeliverSm;
import com.cloudhopper.smpp.util.SmppUtil;
...
DeliverSm mobileOriginatedMessage = (DeliverSm) pduRequest;
boolean isUdh = SmppUtil.isUserDataHeaderIndicatorEnabled(mobileOriginatedMessage.getEsmClass());
if (isUdh) {
byte[] userDataHeader = GsmUtil.getShortMessageUserDataHeader(messageBytes);
int thisMessageId = userDataHeader[3] & 0xff;
int totalMessages = userDataHeader[4] & 0xff;
int currentMessageNum = userDataHeader[5] & 0xff;
messageBytes = GsmUtil.getShortMessageUserData(messageBytes);
GSMCharset gsmCharset = new GSMCharset();
String message = gsmCharset.decode(messageBytes); // Example decoding, depends on charset used
System.out.println("thisMessageId: " + thisMessageId); // unique to message, same across all message parts
System.out.println("totalMessages: " + totalMessages);
System.out.println("currentMessageNum: " + currentMessageNum);
System.out.println("Message: " + message);
}
...
The above shows how to:
Determine if a PDU is multipart long (UDH) message
Get all the UDH header information so you can know
what message the part belongs to
what part number was received in order to put the message back together in the right order
and what the total number of parts you are expecting is
Get the actual message text of each part

JMS selector strange behaviour

In JMS consider the following pseudo-code:
Sender:
QueueSender qs = session.createSender(queue);
int i = 0;
while(i < 10)
{
TextMessage msg = session.createTextMessage();
msg.setText(""+i);
msg.setIntProperty("value", i);
qs.send(msg);
i++;
}
Receiver:
String sel = "value >2";
QueueReceiver qr = session.createReceiver(q,sel);
while(true)
{
TextMessage tm = (TextMessage) qr.receive();
System.out.println(tm.getText);
}
I would have expected the consumer not to consume/print anything becauses the messages he is interested at are blocked by the messages 0,1,2 that are not being pulled by any consumer.
What I see instead is the consumer printing out all the messages selected by its selector...
Is that the correct behaviour of JMS ?
Is that documented somewhere ?
thanks.
I would have expected the consumer not to consume/print anything
becauses the messages he is interested at are blocked by the messages
0,1,2 that are not being pulled by any consumer
This assumption is incorrect. When you use a selector in JMS, the messages that do not satisfy the selector expression will not be delivered to the QueueReceiver. The QueueReciever will continue to read all those messages that satisfy the selector expression.
I believe that your output contains the numbers from 3 - 10. . This is the expected behavior. See the documentation for the createReceiver method.

PUSH Notifications for >1000 devices through GCM Server(Java)

I have a GCM-backend Java server and I'm trying to send to all users a notification msg. Is my approach right? To just split them into 1000 each time before giving the send request? Or is there a better approach?
public void sendMessage(#Named("message") String message) throws IOException {
int count = ofy().load().type(RegistrationRecord.class).count();
if(count<=1000) {
List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).limit(count).list();
sendMsg(records,message);
}else
{
int msgsDone=0;
List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).list();
do {
List<RegistrationRecord> regIdsParts = regIdTrim(records, msgsDone);
msgsDone+=1000;
sendMsg(regIdsParts,message);
}while(msgsDone<count);
}
}
The regIdTrim method
private List<RegistrationRecord> regIdTrim(List<RegistrationRecord> wholeList, final int start) {
List<RegistrationRecord> parts = wholeList.subList(start,(start+1000)> wholeList.size()? wholeList.size() : start+1000);
return parts;
}
The sendMsg method
private void sendMsg(List<RegistrationRecord> records,#Named("message") String message) throws IOException {
if (message == null || message.trim().length() == 0) {
log.warning("Not sending message because it is empty");
return;
}
Sender sender = new Sender(API_KEY);
Message msg = new Message.Builder().addData("message", message).build();
// crop longer messages
if (message.length() > 1000) {
message = message.substring(0, 1000) + "[...]";
}
for (RegistrationRecord record : records) {
Result result = sender.send(msg, record.getRegId(), 5);
if (result.getMessageId() != null) {
log.info("Message sent to " + record.getRegId());
String canonicalRegId = result.getCanonicalRegistrationId();
if (canonicalRegId != null) {
// if the regId changed, we have to update the datastore
log.info("Registration Id changed for " + record.getRegId() + " updating to " + canonicalRegId);
record.setRegId(canonicalRegId);
ofy().save().entity(record).now();
}
} else {
String error = result.getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
log.warning("Registration Id " + record.getRegId() + " no longer registered with GCM, removing from datastore");
// if the device is no longer registered with Gcm, remove it from the datastore
ofy().delete().entity(record).now();
} else {
log.warning("Error when sending message : " + error);
}
}
}
}
Quoting from Google Docs:
GCM is support for up to 1,000 recipients for a single message. This capability makes it much easier to send out important messages to your entire user base. For instance, let's say you had a message that needed to be sent to 1,000,000 of your users, and your server could handle sending out about 500 messages per second. If you send each message with only a single recipient, it would take 1,000,000/500 = 2,000 seconds, or around half an hour. However, attaching 1,000 recipients to each message, the total time required to send a message out to 1,000,000 recipients becomes (1,000,000/1,000) / 500 = 2 seconds. This is not only useful, but important for timely data, such as natural disaster alerts or sports scores, where a 30 minute interval might render the information useless.
Taking advantage of this functionality is easy. If you're using the GCM helper library for Java, simply provide a List collection of registration IDs to the send or sendNoRetry method, instead of a single registration ID.
We can not send more than 1000 push notification at time.I searched a lot but not result then i did this with same approach split whole list in sub lists of 1000 items and send push notification.

Categories