How to write a sender application for ActiveMQ in Node JS - java

I wanted to create implement a JMS sender app for messaging and created the same with JAVA. This is my sample code snippet in Java.
try {
factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("SAMPLEQUEUE");
producer = session.createProducer(destination);
try {
TextMessage message = session.createTextMessage();
message.setText("hello");
producer.send(message);
System.out.println("Sent: " + message.getText());
} catch (IOException e) {
e.printStackTrace();
}
} catch (JMSException e) {
e.printStackTrace();
}
This works fine and I am able to receive the messages with my receiver also. I want to change the sender implementation in Node JS and make it a Node JS application. I am new to Node JS didn't understand much after searching on ActiveMQ in Node JS. Any pointer to it would be really helpful.
Regards,
Subhankar
EDIT
I used stomp for node JS. The sample code is the following :
var Stomp = require('stomp-client');
var destination = '/queue/sensorstreamqueue';
var client = new Stomp('10.53.219.153', 61613, 'user', 'pass');
var lazy = require("lazy"),
fs = require("fs");
client.connect(function(sessionId) {
new lazy(fs.createReadStream('input.csv'))
.lines
.forEach(function(line){
client.publish(destination, line.toString());
}
);
console.log("published");
});
The code works and my receiver also gets the message but then my receiver expects it to be a textMesssage format and gives the following error:
02-19-2015 08:42:31.288 ERROR [Thread-25] (JmsInputTransporter.handleTextMessage) Error code:401306, Severity : 3 (Error)
Error message:JMS Transporter is expected a TextMessage, received class org.apache.activemq.command.ActiveMQBytesMessage.
Error description:JMS Transporter is expected a TextMessage, received class org.apache.activemq.command.ActiveMQBytesMessage.
Can someone help me how can I achieve that?

You can try the activemq-node module, or you can enable the STOMP protocol on ActiveMQ and use this node.js library.

You need to add a header:
client.publish(destination, 'your content', {
"amq-msg-type": "text"
});
https://issues.apache.org/jira/browse/AMQ-2833

Related

How can I catch java.net.SocketException when ActiveMQ is stopped?

I have a consumer Java app which connects to an Apache ActiveMQ server. It's working. However, if I stop the Apache ActiveMQ server the consumer app has an exception:
java.net.SocketException: Connection reset
How can I handle this Exception, for example I'd like to send an alert e-mail to support. How can I detect offline ActiveMQ server.
Here is the exception details
// Getting JMS connection from the server
ActiveMQConnectionFactory activeMQConnectionFactory = new ActiveMQConnectionFactory(this.activeMqClient.getUsername(), this.activeMqClient.getPassword(), this.activeMqClient.getProducerUri());
activeMQConnectionFactory.setUseAsyncSend(false);
activeMQConnectionFactory.setMaxThreadPoolSize(1);
this.activeMqClient.setClientId(activeMqClient.getClientType() + "_" + Thread.currentThread().getName());
if (this.activeMqClient.getClientId() != null) {
activeMQConnectionFactory.setClientID(this.activeMqClient.getClientId());
}
Connection connection = activeMQConnectionFactory.createConnection();
if (this.activeMqClient.getClientId() != null) {
connection.setClientID(this.activeMqClient.getClientId());
}
connection.start();
connection.setExceptionListener(this);
// Creating session for receiving messages
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
// Getting the queue
Destination destination = session.createQueue(this.activeMqClient.getDestinationQueueName() + "?consumer.exclusive=true");
// MessageConsumer is used for receiving (consuming) messages
MessageConsumer consumer = session.createConsumer(destination);
//Setting message listener
consumer.setMessageListener(this);
You can catch it like any other exception:
try {
//... client code ...//
}
catch(SocketException e) {
//... send email ...//
}

JMS Get message/response from EJB

This is my sender class:
private void sendJMSMessage(Object data) throws JMSException {
Connection con = null;
Session s = null;
try {
con = context.createConnection();
s = con.createSession(false, Session.CLIENT_ACKNOWLEDGE);
MessageProducer producer = s.createProducer(glassFishQueue);
ObjectMessage msg = s.createObjectMessage();
ArrayList list = new ArrayList();
list.add("name");
msg.setObject(p);
producer.send(msg);
}
And my Message-driven Bean:
public void onMessage(Message message) {
try {
ObjectMessage om = (ObjectMessage) message;
ArrayList al = (ArrayList) om.getObject();
System.out.println("Msg: " + al.get(0));
} catch (JMSException jex) {
System.out.println("Exception: " + jex);
}
I got the message sent from sender class but I need a message back from EJB to the sender.
Im doing a web client with a table but I need to fill it getting the info from a database remotely, I really doesnt know what i should to use to do this, so if im doing right let me know or tell me any suggestion
Thank u
JMS is asynchronous, so it won't work in request-response style out of the box.
If you want to send a reply, one way is to use a separate queue. Your MDB can write the response to this second queue and your client can listen to this queue by creating a QueueReceiver.
Another way is to use QueueRequestor. From javadocs:
It creates a TemporaryQueue for the responses and provides a request
method that sends the request message and waits for its reply.
Look here and here for QueueRequestor examples.

Implementing ActiveMQ Message Listener in/using JSP

I have implemented Message Listener in core java using Active MQ/JMS. The purpose of this listener is to subscribe a topic on ActiveMQ and then listen to the messages received from the topic. My code is working fine as a console application. Now I need to extend my application into a web application so that the messages received could be used in the web page i.e JSP. I am confused about how the message listener will work in JSP, how I will receive and process messages from active MQ topic. So far I have following code but doesn't seem to help in current scenario:
<%!
public void handleReceivedMessages() {
String url = ActiveMQConnection.DEFAULT_BROKER_URL;
String subject = "XXXXX";
try {
ConnectionFactory connectionFactory
= new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Topic topic = session.createTopic(subject);
MessageConsumer consumer = session.createConsumer(topic);
MessageListener listner = new MessageListener() {
#Override
public void onMessage(Message message) {
try {
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
System.out.println("Received message : "
+ textMessage.getText() + "'");
}
} catch (JMSException e) {
System.out.println("Caught:" + e);
}
}
};
consumer.setMessageListener(listner);
try {
System.in.read();
} catch (IOException e) {
}
connection.close();
} catch (JMSException ex) {
// Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, ex);
}
}//end method
%>
How I am supposed to use this code so that i can e.g print every message on my web page which is received by the topic?
JSP pages are used the moment the web page is loaded to render the HTML. After that, they have no function.
Typically, you need to create a Message Driven Bean(MDB) or something similar using Spring. The MDB will receive messages, process the data and store it somewhere (typically a database, but could be also be a global cache, local files or similar). Your JSP then simply uses the data stored by JMS messages.
If you really want the messages to interact with the user more dynamically - you can connect to ActiveMQ using JavaScript from the client browser. The ActiveMQ distribution have some examples regarding this. Look into examples/mqtt/websocket or examples/stomp/websocket to see some working code.

Not receiving reply on Websphere MQ temporary queue

I am working with a send/receive mechanism to a Websphere MQ system.
The xml that I send in text format should receive a reply, however I receive no reply.
I know that the xml is being "sent" ok, since "things are happening" in the target system - it is just that I am not receiving a reply. The reply is important to me, since it could include an error message if something should fail.
So, the reason I am not receiving a reply - I am not sure if there is a problem with my code or with the Websphere MQ configuration.
Any pointers on my code or what I should ask the Websphere MQ administrators to look at are greatly appreciated!!
A small self contained example to demonstrate the receive is not happening looks like this:
public class CustomQueueConnection {
private MQQueueConnectionFactory connectionFactory;
private MQQueueConnection connection;
private void runTest() throws JMSException {
connect();
MQQueueSession session = (MQQueueSession) connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
MQQueue queue = (MQQueue) session.createQueue("queue:///REQ_SNAPSHOT.HT");
MQQueueSender sender = (MQQueueSender) session.createSender(queue);
TemporaryQueue temporaryQueue = session.createTemporaryQueue();
MQQueueReceiver receiver = (MQQueueReceiver) session.createReceiver(temporaryQueue);
TextMessage message = session.createTextMessage(
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n" +
// my well constructed xml goes here...
);
message.setJMSReplyTo(temporaryQueue);
sender.send(message);
System.out.println("Sent: " + message);
JMSMessage receivedMessage = (JMSMessage) receiver.receive(10000);
System.out.println("Received: " + receivedMessage);
}
public boolean connect() {
boolean connected = false;
try {
connectionFactory = new MQQueueConnectionFactory();
connectionFactory.setCCSID(819);
connectionFactory.setPort(1417);
connectionFactory.setHostName("1.2.3.4");
connectionFactory.setQueueManager("GATE1");
connectionFactory.setChannel("CLIENTS.CHANNEL");
connectionFactory.setTemporaryModel("GATEWAY_MODEL_QUEUE");
connectionFactory.setTempQPrefix("MACHINE.USER_NAME.*");
connectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
connection = (MQQueueConnection) connectionFactory.createQueueConnection();
connected = true;
} catch (JMSException e) {
connected = false;
}
return connected;
}
public static void main(String[] args) throws JMSException {
new CustomQueueConnection().runTest();
}
}
And here is the output:
Sent:
JMS Message class: jms_text
JMSType: null
JMSDeliveryMode: 2
JMSExpiration: 0
JMSPriority: 4
JMSMessageID: ID:414d512050314f47415445312020202053599032201b4d05
JMSTimestamp: 1398680728618
JMSCorrelationID:null
JMSDestination: queue:///REQ_SNAPSHOT.HT
JMSReplyTo: queue://GATE1/MACHINE.USER_NAME.53599032201B4E04?persistence=1
JMSRedelivered: false
JMS_IBM_PutDate:20140428
JMSXAppID:WebSphere MQ Client for Java
JMS_IBM_PutApplType:28
JMSXUserID:aomis
JMS_IBM_PutTime:10252859
JMSXDeliveryCount:0
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<esb:esbMessage xmlns:esb="http://ESBServices
Another 557 character(s) omitted
Received: null
(NB: Received: null)
edit: Websphere MQ version is 6.0.25
Your code looks OK to me, message send is successful. I would like you to check:
1) Is there an application running to receive message from REQ_SNAPSHOT.HT queue?
2) Assuming there is an application running and receiving messages, has that application processed the incoming XML message successfully? is it throwing any exceptions?
3) If the incoming message is processed successfully, has it put a reply to the correct reply queue "MACHINE.USER_NAME.53599032201B4E04"? check if it faced any problems while putting the reply message.
The solution was twofold.
First, the connection needed to be started right after it was created.
connect();
connection.start();
Secondly, the message needed to be sent with DeliveryMode.NON_PERSISTENT.

ActiveMQ and embedded broker

EDIT: Rephrased the question:
I want to use ActiveMQ as a messenger service between my server and client applications.
I am trying to set up an embedded broker (i.e. not a separate process) within the server to handle the produced messages for my clients to consume. This queue is persisted.
The broker initialisation as follows:
BrokerService broker = new BrokerService();
KahaPersistenceAdapter adaptor = new KahaPersistenceAdapter();
adaptor.setDirectory(new File("activemq"));
broker.setPersistenceAdapter(adaptor);
broker.setUseJmx(true);
broker.addConnector("tcp://localhost:61616");
broker.start();
After tinkering, I ended up with the server part being:
public static class HelloWorldProducer implements Runnable {
public void run() {
try {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost"); // apparently the vm part is all i need
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("TEST.FOO");
MessageProducer producer = session.createProducer(destination);
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
String text = "Hello world! From: " + Thread.currentThread().getName() + " : " + this.hashCode();
TextMessage message = session.createTextMessage(text);
System.out.println("Sent message: "+ message.hashCode() + " : " + Thread.currentThread().getName());
producer.send(message);
session.close();
connection.close();
}
catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
}
The client is very similar and looks like this:
public static class HelloWorldConsumer implements Runnable, ExceptionListener {
public void run() {
try {
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost");
Connection connection = connectionFactory.createConnection(); // exception happens here...
connection.start();
connection.setExceptionListener(this);
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("TEST.FOO");
MessageConsumer consumer = session.createConsumer(destination);
Message message = consumer.receive(1000);
if (message instanceof TextMessage) {
TextMessage textMessage = (TextMessage) message;
String text = textMessage.getText();
System.out.println("*****Received: " + text);
} else {
System.out.println("*****Received obj: " + message);
}
consumer.close();
session.close();
connection.close();
} catch (Exception e) {
System.out.println("Caught: " + e);
e.printStackTrace();
}
}
The main method simply starts each of these in a thread to start producing/receiving messages.
...but I am running into the following with the start of each thread:
2013-01-24 07:54:31,271 INFO [org.apache.activemq.broker.BrokerService] Using Persistence Adapter: AMQPersistenceAdapter(activemq-data/localhost)
2013-01-24 07:54:31,281 INFO [org.apache.activemq.store.amq.AMQPersistenceAdapter] AMQStore starting using directory: activemq-data/localhost
2013-01-24 07:54:31,302 INFO [org.apache.activemq.kaha.impl.KahaStore] Kaha Store using data directory activemq-data/localhost/kr-store/state
2013-01-24 07:54:31,339 INFO [org.apache.activemq.store.amq.AMQPersistenceAdapter] Active data files: []
2013-01-24 07:54:31,445 DEBUG [org.apache.activemq.broker.jmx.ManagementContext] Probably not using JRE 1.4: mx4j.tools.naming.NamingService
2013-01-24 07:54:31,450 DEBUG [org.apache.activemq.broker.jmx.ManagementContext] Failed to create local registry
java.rmi.server.ExportException: internal error: ObjID already in use
at sun.rmi.transport.ObjectTable.putTarget(ObjectTable.java:186)
at sun.rmi.transport.Transport.exportObject(Transport.java:92)
at sun.rmi.transport.tcp.TCPTransport.exportObject(TCPTransport.java:247)
at sun.rmi.transport.tcp.TCPEndpoint.exportObject(TCPEndpoint.java:411)
at sun.rmi.transport.LiveRef.exportObject(LiveRef.java:147)
<snip....>
It seems like the messages are produced and consumed successfully (the other issues I previously posted about was resolved), but the above exception is worrying me.
EDIT: During broker shutdown, I am now also greeted by the following:
2013-01-25 08:40:17,486 DEBUG [org.apache.activemq.transport.failover.FailoverTransport] Transport failed with the following exception:
java.io.EOFException
at java.io.DataInputStream.readInt(DataInputStream.java:392)
at org.apache.activemq.openwire.OpenWireFormat.unmarshal(OpenWireFormat.java:269)
at org.apache.activemq.transport.tcp.TcpTransport.readCommand(TcpTransport.java:210)
at org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:202)
at org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:185)
at java.lang.Thread.run(Thread.java:722)
You can embed a broker into your code in a number of ways, much of which is documented here. You may want to try upgrading you version since what you are using appears to be quite old as it defaulting to the now deprecated AMQ Store instead of the newer KahaDB store. You might be having issues because of a race between the client threads as they use the different connection factories which could race to create in VM brokers. If you set the create=false option on the producer and ensure the consumer thread starts after that could address the issue, or you could create the VM broker ahead of time and the add create=false to both thread's and that might do the trick.
BrokerService broker = new BrokerService();
// configure the broker
broker.setBrokerName("localhost");
broker.setUseJmx(false);
broker.start();
And then in the client code just attach via this connection factory configuration.
ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory("vm://localhost?create=false");
When I run your code, I got the below exception:
javax.jms.JMSException: Could not connect to broker URL: tcp://localhost.
Reason java.lang.IllegalArgumentException: port out of range:-1
Your broker is running and listening to port 61616, so any client which tries to connect to broker need to have the port in its URL.
The client code tries to connect to localhost but doesn't mention the port to which it has to connect.
Both the producer and consumer code needs to be fixed.
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost");
To
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
After fixing the port, I was able to run your code.

Categories

Resources