I have created Simple JMS Client and Receiver Program. I have used JDk1.7 and activeMQ 5.10.0.My Sender code is executing with particlur message
MessageProducer mp= session.createProducer(destinatin);
Message message = session.createTextMessage("Hi Welcome to ActiveMQ Example");
mp.send(message);
System.out.println("Message Has Sent");
and
Receiver code My Reciver Code is this one where it is not printing anything.
and after some time it gives me error of connection timeout.Could you find out where I am creating mistake...
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://Name-PC:61616");
//connectin creation
Connection con = connectionFactory.createConnection();
Session session = con.createSession(false,Session.AUTO_ACKNOWLEDGE);
Destination dest= new ActiveMQQueue("Test1.Queue");
MessageConsumer Consumer = session.createConsumer(dest);
Message message = Consumer .receive();
System.out.println("End of Message1");
TextMessage text = (TextMessage) message;
System.out.println("Message" +text.getText());
System.out.println("End of Message");
In http://localhost:8161/admin/queues.jsp it is showing content on
Name Test1.Queue, Number Of Pending Messages =1, Number Of Consumers=1 Messages Enqueued =1,but Messages Dequeued not showing anything
You need to start the connection.
This groovy code works for me:
factory = new ActiveMQConnectionFactory("tcp://tpmint:61616");
dest = new ActiveMQQueue("foo.bar");
conn = null;
session = null;
consumer = null;
try {
conn = factory.createConnection();
println "Connected: $conn";
session = conn.createSession(false,Session.AUTO_ACKNOWLEDGE);
println "Session: $session";
consumer = session.createConsumer(dest);
println "Consumer: $consumer";
conn.start();
msg = consumer.receive(1000);
if(msg==null) println "Timeout";
else println "Msg:$msg";
} finally {
if(consumer!=null) try { consumer.close(); println "Consumer Closed";} catch (e) {}
if(session!=null) try { session.close(); println "Session Closed";} catch (e) {}
if(conn!=null) try { conn.close(); println "Connection Closed"; } catch (e) {e.printStackTrace(System.err);}
}
Output:
Connected: ActiveMQConnection {id=ID:tpmint-51137-1445798087365-0:8,clientId=null,started=false}
Session: ActiveMQSession {id=ID:tpmint-51137-1445798087365-0:8:1,started=false}
Consumer: ActiveMQMessageConsumer { value=ID:tpmint-51137-1445798087365-0:8:1:1, started=false }
Msg:ActiveMQTextMessage {commandId = 7, responseRequired = false, messageId = ID:tpmint-58446-1445793097761-4:2:1:1:3, originalDestination = null, originalTransactionId = null, producerId = ID:tpmint-58446-1445793097761-4:2:1:1, destination = queue://foo.bar, transactionId = null, expiration = 0, timestamp = 1445798905534, arrival = 0, brokerInTime = 1445798905534, brokerOutTime = 1445802982704, correlationId = , replyTo = null, persistent = false, type = , priority = 0, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = null, marshalledProperties = org.apache.activemq.util.ByteSequence#5346e84e, dataStructure = null, redeliveryCounter = 2, size = 0, properties = {JMSXMessageCounter=1}, readOnlyProperties = true, readOnlyBody = true, droppable = false, text = hey hey}
Consumer Closed
Session Closed
Connection Closed
Related
I'm sending a message to "config" topic from my Spring boot backend application
Here's my mqtt setup
final String mqttServerAddress =
String.format("ssl://%s:%s", options.mqttBridgeHostname, options.mqttBridgePort);
// Create our MQTT client. The mqttClientId is a unique string that identifies this device. For
// Google Cloud IoT Core, it must be in the format below.
final String mqttClientId =
String.format(
"projects/%s/locations/%s/registries/%s/devices/%s",
options.projectId, options.cloudRegion, options.registryId, options.deviceId);
MqttConnectOptions connectOptions = new MqttConnectOptions();
// Note that the Google Cloud IoT Core only supports MQTT 3.1.1, and Paho requires that we
// explictly set this. If you don't set MQTT version, the server will immediately close its
// connection to your device.
connectOptions.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1_1);
Properties sslProps = new Properties();
sslProps.setProperty("com.ibm.ssl.protocol", "TLSv1.2");
connectOptions.setSSLProperties(sslProps);
// With Google Cloud IoT Core, the username field is ignored, however it must be set for the
// Paho client library to send the password field. The password field is used to transmit a JWT
// to authorize the device.
connectOptions.setUserName(options.userName);
DateTime iat = new DateTime();
if ("RS256".equals(options.algorithm)) {
connectOptions.setPassword(
createJwtRsa(options.projectId, options.privateKeyFile).toCharArray());
} else if ("ES256".equals(options.algorithm)) {
connectOptions.setPassword(
createJwtEs(options.projectId, options.privateKeyFileEC).toCharArray());
} else {
throw new IllegalArgumentException(
"Invalid algorithm " + options.algorithm + ". Should be one of 'RS256' or 'ES256'.");
}
// [START iot_mqtt_publish]
// Create a client, and connect to the Google MQTT bridge.
MqttClient client = new MqttClient(mqttServerAddress, mqttClientId, new MemoryPersistence());
// Both connect and publish operations may fail. If they do, allow retries but with an
// exponential backoff time period.
long initialConnectIntervalMillis = 500L;
long maxConnectIntervalMillis = 6000L;
long maxConnectRetryTimeElapsedMillis = 900000L;
float intervalMultiplier = 1.5f;
long retryIntervalMs = initialConnectIntervalMillis;
long totalRetryTimeMs = 0;
while ((totalRetryTimeMs < maxConnectRetryTimeElapsedMillis) && !client.isConnected()) {
try {
client.connect(connectOptions);
} catch (MqttException e) {
int reason = e.getReasonCode();
// If the connection is lost or if the server cannot be connected, allow retries, but with
// exponential backoff.
System.out.println("An error occurred: " + e.getMessage());
if (reason == MqttException.REASON_CODE_CONNECTION_LOST
|| reason == MqttException.REASON_CODE_SERVER_CONNECT_ERROR) {
System.out.println("Retrying in " + retryIntervalMs / 1000.0 + " seconds.");
Thread.sleep(retryIntervalMs);
totalRetryTimeMs += retryIntervalMs;
retryIntervalMs *= intervalMultiplier;
if (retryIntervalMs > maxConnectIntervalMillis) {
retryIntervalMs = maxConnectIntervalMillis;
}
} else {
throw e;
}
}
}
attachCallback(client, options.deviceId);
// The MQTT topic that this device will publish telemetry data to. The MQTT topic name is
// required to be in the format below. Note that this is not the same as the device registry's
// Cloud Pub/Sub topic.
String mqttTopic = String.format("/devices/%s/%s", options.deviceId, options.messageType);
long secsSinceRefresh = ((new DateTime()).getMillis() - iat.getMillis()) / 1000;
if (secsSinceRefresh > (options.tokenExpMins * MINUTES_PER_HOUR)) {
System.out.format("\tRefreshing token after: %d seconds%n", secsSinceRefresh);
iat = new DateTime();
if ("RS256".equals(options.algorithm)) {
connectOptions.setPassword(
createJwtRsa(options.projectId, options.privateKeyFile).toCharArray());
} else if ("ES256".equals(options.algorithm)) {
connectOptions.setPassword(
createJwtEs(options.projectId, options.privateKeyFileEC).toCharArray());
} else {
throw new IllegalArgumentException(
"Invalid algorithm " + options.algorithm + ". Should be one of 'RS256' or 'ES256'.");
}
client.disconnect();
client.connect(connectOptions);
attachCallback(client, options.deviceId);
}
MqttMessage message = new MqttMessage(data.getBytes(StandardCharsets.UTF_8.name()));
message.setQos(1);
client.publish(mqttTopic, message);
here's the options class
public class MqttExampleOptions {
String mqttBridgeHostname = "mqtt.googleapis.com";
short mqttBridgePort = 8883;
String projectId =
String cloudRegion = "europe-west1";
String userName = "unused";
String registryId = <I don't want to show>
String gatewayId = <I don't want to show>
String algorithm = "RS256";
String command = "demo";
String deviceId = <I don't want to show>
String privateKeyFile = "rsa_private_pkcs8";
String privateKeyFileEC = "ec_private_pkcs8";
int numMessages = 100;
int tokenExpMins = 20;
String telemetryData = "Specify with -telemetry_data";
String messageType = "config";
int waitTime = 120
}
When I try to publish message to topic "config" I get this error
ERROR 12556 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[.[dispatcherServlet] : Servlet.service()
for servlet [dispatcherServlet] in context with path [/iot-admin] threw exception [Request processing failed; nested exception is Connection Lost (32109) - java.io.EOFException] with root cause
java.io.EOFException: null
at java.base/java.io.DataInputStream.readByte(DataInputStream.java:273) ~[na:na]
at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:92) ~[org.eclipse.paho.client.mqttv3-1.2.5.jar:na]
at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:137) ~[org.eclipse.paho.client.mqttv3-1.2.5.jar:na]
this is the message I am sending
{
"Led": {
"id": "e36b5877-2579-4db1-b595-0e06410bde11",
"rgbColors": [{
"id": "1488acfe-baa7-4de8-b4a2-4e01b9f89fc5",
"configName": "Terminal",
"rgbColor": [150, 150, 150]
}, {
"id": "b8ce6a35-4219-4dba-a8de-a9070f17f1d2",
"configName": "PayZone",
"rgbColor": [150, 150, 150]
}, {
"id": "bf62cef4-8e22-4804-a7d8-a0996bef392e",
"configName": "PayfreeLogo",
"rgbColor": [150, 150, 150]
}, {
"id": "c62d25a4-678b-4833-9123-fe3836863400",
"configName": "BagDetection",
"rgbColor": [200, 200, 200]
}, {
"id": "e19e1ff3-327e-4132-9661-073f853cf913",
"configName": "PersonDetection",
"rgbColor": [150, 150, 150]
}]
}
}
How can I properly send a message to a config topic without getting this error? I am able to send message to "state" topic, but not to "config" topic.
I am wring custom java code to read messages from Websphere MQ (version 8) and read all the headers from the MQ message.
When I use the MQHeaderList to parse all the headers the list size is 0:
MQMessage message = new MQMessage();
queue.get(message, getOptions);
DataInput in = new DataInputStream (new ByteArrayInputStream (b));
MQHeaderList headersfoundlist = null;
headersfoundlist = new MQHeaderList (in);
System.out.println("headersfoundlist size: " + headersfoundlist.size());
However, I read only a specific MQRFH2 it works
MQMessage message = new MQMessage();
queue.get(message, getOptions);
DataInput in = new DataInputStream (new ByteArrayInputStream (b));
MQRFH2 rfh2 = new MQRFH2(in);
Element usrfolder = rfh2.getFolder("usr", false);
System.out.println("usr folder" + usrfolder);
How can I parse all the headers of the MQ Message?
DataInput in = new DataInputStream (new ByteArrayInputStream (b));
What's that about? Not sure why you want to do that.
It should just be:
MQMessage message = new MQMessage();
queue.get(message, getOptions);
MQHeaderList headersfoundlist = new MQHeaderList(message);
System.out.println("headersfoundlist size: " + headersfoundlist.size());
Read more here.
Update:
#anshu's comment about it not working, well, I've always found MQHeaderList class to be very buggy. Hence, that is why I don't use it.
Also, 99.99% messages in MQ will only ever have 1 embedded MQ header (i.e. MQRFH2). Note: A JMS message == MQRFH2 message. The only case where you will find 2 embedded MQ headers are for messages on the Dead Letter Queue.
i.e.
{MQDLH}{MQRFH2}{message payload}
Is there a real need for your application to process multiple embedded MQ headers? Is your application putting/getting JMS messages (aka MQRFH2 messages)?
If so then you should do something like the following:
queue.get(receiveMsg, gmo);
if (CMQC.MQFMT_RF_HEADER_2.equals(receiveMsg.format))
{
receiveMsg.seek(0);
MQRFH2 rfh2 = new MQRFH2(receiveMsg);
int strucLen = rfh2.getStrucLength();
int encoding = rfh2.getEncoding();
int CCSID = rfh2.getCodedCharSetId();
String format= rfh2.getFormat();
int flags = rfh2.getFlags();
int nameValueCCSID = rfh2.getNameValueCCSID();
String[] folderStrings = rfh2.getFolderStrings();
for (String folder : folderStrings)
System.out.println.logger("Folder: "+folder);
if (CMQC.MQFMT_STRING.equals(format))
{
String msgStr = receiveMsg.readStringOfByteLength(receiveMsg.getDataLength());
System.out.println.logger("Data: "+msgStr);
}
else if (CMQC.MQFMT_NONE.equals(format))
{
byte[] b = new byte[receiveMsg.getDataLength()];
receiveMsg.readFully(b);
System.out.println.logger("Data: "+new String(b));
}
}
else if ( (CMQC.MQFMT_STRING.equals(receiveMsg.format)) ||
(CMQC.MQFMT_NONE.equals(receiveMsg.format)) )
{
Enumeration<String> props = receiveMsg.getPropertyNames("%");
if (props != null)
{
System.out.println.logger("Named Properties:");
while (props.hasMoreElements())
{
String propName = props.nextElement();
Object o = receiveMsg.getObjectProperty(propName);
System.out.println.logger(" Name="+propName+" : Value="+o);
}
}
if (CMQC.MQFMT_STRING.equals(receiveMsg.format))
{
String msgStr = receiveMsg.readStringOfByteLength(receiveMsg.getMessageLength());
System.out.println.logger("Data: "+msgStr);
}
else
{
byte[] b = new byte[receiveMsg.getMessageLength()];
receiveMsg.readFully(b);
System.out.println.logger("Data: "+new String(b));
}
}
else
{
byte[] b = new byte[receiveMsg.getMessageLength()];
receiveMsg.readFully(b);
System.out.println.logger("Data: "+new String(b));
}
I found the mistake in my code. I have a few more steps before reading the headers. It was moving the cursor in message buffer to the end.
I added message.setDataOffset(0); before reading headers and it worked.
public string WriteMsg(string strInputMsg)
{
string strReturn = "";
try
{
MQQueue queue = null;
MQQueueManager QueueManagerName = null ;
QueueManagerName = new MQQueueManager("GRBAAQM");
queue = QueueManagerName.AccessQueue(QueueName, MQC.MQOO_OUTPUT
+ MQC.MQOO_FAIL_IF_QUIESCING);
message = strInputMsg;
queueMessage = new MQMessage();
queueMessage.WriteString(message);
queueMessage.Format = MQC.MQFMT_STRING;
queuePutMessageOptions = new MQPutMessageOptions();
queue.Put(queueMessage, queuePutMessageOptions);
strReturn = "Message sent to the queue successfully";
}
catch (MQException MQexp)
{
strReturn = "Exception: " + MQexp.Message;
}
catch (Exception exp)
{
strReturn = "Exception: " + exp.Message;
}
return strReturn;
}
public string ReadMsg()
{
String strReturn = "";
try
{
MQQueue queue = null;
MQQueueManager QueueManagerName = null;
QueueManagerName = new MQQueueManager("GRBAAQM");
queue = QueueManagerName.AccessQueue(QueueName, MQC.MQOO_INPUT_AS_Q_DEF +
MQC.MQOO_FAIL_IF_QUIESCING);
queueMessage = new MQMessage();
queueMessage.Format = MQC.MQFMT_STRING;
queueGetMessageOptions = new MQGetMessageOptions();
queue.Get(queueMessage, queueGetMessageOptions);
strReturn =
queueMessage.ReadString(queueMessage.MessageLength);
}
catch (MQException MQexp)
{
strReturn = "Exception : " + MQexp.Message;
}
catch (Exception exp)
{
strReturn = "Exception: " + exp.Message;
}
return strReturn;
}
These two methods in this program helps us to read the messages from queue and displays but how to insert this feature while reading message FROM queue, read only if the message count has reached 10.
Why do you care how many messages are in the queue? MQ is NOT a database. If a message is in the queue then it should be processed. If you need to group messages together then have the sender use MQ's message grouping feature.
Did you read about MQ triggering? A program can be triggered (started) based on a triggering event. i.e. Trigger-first, trigger-every & trigger-depth.
I am trying to read the state string for messages on a queue
I am using the following code to read the state string, but state string always returns ""
JmsMessageDetailsBag detailsBag = new JmsMessageDetailsBag();
try {
InitialContext ctx = OpenTwinsFrontendUtilities.getInitialContext( false );
// lookup the queue object
Queue queue = (Queue) ctx.lookup( queueName );
// lookup the queue connection factory
QueueConnectionFactory connFactory = (QueueConnectionFactory) ctx.lookup( "jms/EJBJMSQueueConnectionFactory" );
// create a queue connection
QueueConnection queueConn = connFactory.createQueueConnection();
// create a queue session
QueueSession queueSession = queueConn.createQueueSession( false, Session.AUTO_ACKNOWLEDGE );
// create a queue browser
QueueBrowser queueBrowser = queueSession.createBrowser( queue );
// start the connection
queueConn.start();
// browse the messages
Enumeration<?> e = queueBrowser.getEnumeration();
// count number of messages
while ( e.hasMoreElements() ) {
javax.jms.Message message = (javax.jms.Message) e.nextElement();
JmsMessageDetails details = new JmsMessageDetails();
weblogic.jms.extensions.JMSMessageInfo info = new weblogic.jms.extensions.JMSMessageInfo( ((weblogic.jms.extensions.WLMessage) message) );
details.setMessageState( info.getStateString( info.getState() != 0 ? info.getState() : 1 ) );
details.setMessageId( message.getJMSMessageID() );
details.setTimeStamp( new OpenTwinsDateAndTimeImpl( new Date( message.getJMSTimestamp() ) ) );
details.setMessageBody( new OpenTwinsCLOBImpl( JsonJMSMessage.serializerPretty.toJson( message ) ) );
detailsBag.add( details );
}
But info.getState() always returns 0;
Is there some other way to get the correct state
I have a simple spring jms tutorial.A lender is acting as receiver. A borrower is action as sender. borrower sends salary and loan amount, and waits for response. The lender runs a decision and sends back "accept" or "decline".
on the borrower side, i am doing the following.
Message sentMessage = (Message)jmsTemplate.execute(new MyProducerCallBack(messageMap, "lenderResponseQueue"));
String filter = "JMSCorrelationID = '" + sentMessage.getJMSMessageID() + "'";
TextMessage tmsg = (TextMessage) jmsTemplate.receiveSelected("lenderResponseQueue", filter);
This is the code in MyProducerCallBack
public Object doInJms(Session session, MessageProducer producer) throws JMSException {
System.out.println("inside doInJms");
//create queue to receive accept or decline from lender
Queue queue = session.createQueue(lenderResponseQueue);
MapMessage jmsMapMsg = session.createMapMessage();
populateJMSMapMsg(jmsMapMsg, mapMessage);
jmsMapMsg.setJMSReplyTo(queue);
//send salary and loan amount to lender
producer.send(jmsMapMsg);
//get the accept or decline from lender
Message msg = session.createConsumer(queue).receive();
if(msg instanceof TextMessage){
System.out.println(((TextMessage)msg).getText());
}
return msg;
}
When Message msg = session.createConsumer(queue).receive(); is encountered The logs throw the following exception
2011-10-19 20:21:03,458 WARN [org.apache.activemq.ActiveMQSessionExecutor] - Received a message on a connection which is not yet started.
Have you forgotten to call Connection.start()? Connection: ActiveMQConnection {id=ID:Reverb0253-PC-54217-1319070060323-0:1,clientId=ID:Reverb0253-PC-54217-1319070060323-1:1,started=false}
Received: MessageDispatch {commandId = 0, responseRequired = false, consumerId = ID:Reverb0253-PC-54217-1319070060323-0:1:1:1, destination = queue://lenderResponseQueue, message =
ActiveMQTextMessage {commandId = 7, responseRequired = true, messageId = ID:Reverb0253-PC-52978-1319058441747-0:1:1:1:1, originalDestination = null, originalTransactionId = null, producerId = ID:Reverb0253-PC-52978-1319058441747-0:1:1:1, destination = queue://lenderResponseQueue, transactionId = null, expiration = 0, timestamp = 1319058485680, arrival = 0, brokerInTime = 1319058485706, brokerOutTime = 1319070063443, correlationId = ID:Reverb0253-PC-53001-1319058485443-0:1:1:1:1, replyTo = null, persistent = true, type = null, priority = 4, groupID = null, groupSequence = 0, targetConsumerId = null, compressed = false, userID = null, content = null, marshalledProperties = null, dataStructure = null, redeliveryCounter = 5, size = 0, properties = null, readOnlyProperties = true, readOnlyBody = true, droppable = false, text = Accepted!}, redeliveryCounter = 5}
The receiving queue is lenderResponseQueue is not present in the spring config file. Do I need to specify it there. This is my jmsTemplate from config file
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="queueConnectionFactory"/>
<property name="destinationResolver" ref="destinationResolver"/>
<!-- name of destination -->
<property name="defaultDestinationName" value="lenderRequestQueue"/>
<!-- amount of time to wait before getting a message -->
<property name="receiveTimeout" value="0"/>
<!-- indicate weather queue or topic is used. false = queue or p2p -->
<property name="pubSubDomain" value="false"/>
</bean>
Is there any specific reason you have both send and receive in the execute callback right after one another:
//send salary and loan amount to lender
producer.send(jmsMapMsg);
//get the accept or decline from lender
Message msg = session.createConsumer(queue).receive();
You would usually receive in a separate JmsTemplate.receive() call ( not within a callback ). That would decouple / unsync your callback, as well as most likely would solve your:
Received a message on a connection which is not yet started.