JBoss 7 Embedded ActiveMQ - MDB message listener not working - activemq

I have to upgrade an existing app with JBOSS 4.2.2 and embedded activeMQ 5.3.0
To try with jboss 7.3 using an embedded active MQ, i did the following.
Following the instructions at https://developer.jboss.org/docs/DOC-18798#jive_content_id_ActiveMQ_as_an_internal_messaging_broker
I configured the activemq-rar-5.6.0.rar in JBoss 7.3 resource-adapter
Deployed the jboss quick start hello-world-mdb war file in jboss.
Tried to send and consume messages using a message driven bean(MDB)
The problem I am facing is, I don't see the Messages being consumed by the message listener.
Below are my configurations
1.resource-adapters subsystem changes in standalone-full.xml file
<subsystem xmlns="urn:jboss:domain:resource-adapters:5.0">
<resource-adapters>
<resource-adapter id="activemq-rar-5.6.0.rar">
<archive>
activemq-rar-5.6.0.rar
</archive>
<transaction-support>XATransaction</transaction-support>
<!--<config-property name="ServerUrl">tcp://localhost:61616</config-property> -->
<config-property name="ServerUrl">vm://localhost</config-property>
<connection-definitions>
<connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/activemq/ConnectionFactory" enabled="true" use-java-context="true" pool-name="ActiveMQConnectionFactoryPool" use-ccm="true">
<xa-pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>20</max-pool-size>
</xa-pool>
</connection-definition>
</connection-definitions>
<admin-objects>
<admin-object class-name="org.apache.activemq.command.ActiveMQQueue" jndi-name="java:/queue/HELLOWORLDMDBQueue" use-java-context="true" pool-name="HELLOWORLDMDBQueue">
<config-property name="PhysicalName">HELLOWORLDMDBQueue</config-property>
</admin-object>
<admin-object class-name="org.apache.activemq.command.ActiveMQTopic" jndi-name="java:/topic/HELLOWORLDMDBTopic" use-java-context="true" pool-name="HELLOWORLDMDBTopic">
<config-property name="PhysicalName">HELLOWORLDMDBTopic</config-property>
</admin-object>
</admin-objects>
</resource-adapter>
</resource-adapters>
</subsystem>
standalone-full.xml domain:ejb3 subsystem mdb changes
<mdb>
<resource-adapter-ref resource-adapter-name="activemq-rar-5.6.0.rar"/>
<bean-instance-pool-ref pool-name="mdb-strict-max-pool"/>
</mdb>
The helloworld-mdb.war consists the following two classes.
Message sender
#WebServlet("/HelloWorldMDBServletClient")
public class HelloWorldMDBServletClient extends HttpServlet {
private static final long serialVersionUID = -1949285948189796311L;
#Resource(mappedName = "java:/activemq/ConnectionFactory")
private ConnectionFactory connectionFactory;
#Resource(mappedName = "java:/queue/HELLOWORLDMDBQueue")
private Destination queue;
private Connection connection;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Session session = null;
MessageProducer sender = null;
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.write(
"<h1>Quickstart: Example demonstrates the use of <strong>JMS 2.0</strong> and <strong>EJB 3.2 Message-Driven Bean</strong> in JBoss EAP.</h1>");
try {
connection = connectionFactory.createConnection();
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
sender = session.createProducer(queue);
sender.setDeliveryMode(DeliveryMode.PERSISTENT);
out.write("<p>Sending messages to <em>" + queue + "</em></p>");
out.write("<h2>The following messages will be sent to the destination:</h2>");
for (int i = 0; i < 3; i++) {
String text = "This is message " + (i + 1);
TextMessage response = session.createTextMessage(text);
sender.send(response);
out.write("Message (" + i + "): " + text + "</br>");
}
out.write(
"<p><i>Go to your JBoss EAP server console or server log to see the result of messages processing.</i></p>");
} catch (JMSException e) {
e.printStackTrace();
}finally {
try {
if (sender != null) {
sender.close();
}
if (session != null) {
session.close();
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Message Consumer MDB
#MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
#ActivationConfigProperty(propertyName = "destination", propertyValue = "HELLOWORLDMDBQueue"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
#ResourceAdapter(value="activemq-rar-5.6.0.rar")
public class HelloWorldQueueMDB implements MessageListener {
private static final Logger LOGGER = Logger.getLogger(HelloWorldQueueMDB.class.toString());
/**
* #see MessageListener#onMessage(Message)
*/
public void onMessage(Message rcvMessage) {
TextMessage msg = null;
try {
if (rcvMessage instanceof TextMessage) {
msg = (TextMessage) rcvMessage;
LOGGER.info("Received Message from queue: " + msg.getText());
} else {
LOGGER.warning("Message of wrong type: " + rcvMessage.getClass().getName());
}
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
}
I send messages from the browser by going to http://localhost:8080/helloworld-mdb/HelloWorldMDBServletClient.
But I am not seeing the messages being consumed by the message listener, they are not showing in the jboss log.
The JBoss console log looks like this

In the HelloWorldMDBServletClient you're creating a transacted session to send the messages, i.e.:
session = connection.createSession(true, Session.AUTO_ACKNOWLEDGE);
However, you're never calling session.commit() so it looks to me like the messages are never actually sent.
You should either invoke session.commit() to send the messages or create the session as non-transacted, e.g.:
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

Related

TCP Server configuration in Mule - writing into client socket

I am trying to create a mule flow with a TCP inbound endpoint which is a TCP server that listens to a port. When a successful client connection is identified, before receiving any request from the client, I need to write a message into the socket (which lets the client know that I am listening), only after which the client sends me further requests. This is how I do it with a sample java program :
import java.net.*;
import java.io.*;
public class TCPServer
{
public static void main(String[] args) throws IOException
{
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(4445);
}
catch (IOException e)
{
System.err.println("Could not listen on port: 4445.");
System.exit(1);
}
Socket clientSocket = null;
System.out.println ("Waiting for connection.....");
try {
clientSocket = serverSocket.accept();
}
catch (IOException e)
{
System.err.println("Accept failed.");
System.exit(1);
}
System.out.println ("Connection successful");
System.out.println ("Sending output message - .....");
//Sending a message to the client to indicate that the server is active
PrintStream pingStream = new PrintStream(clientSocket.getOutputStream());
pingStream.print("Server listening");
pingStream.flush();
//Now start listening for messages
System.out.println ("Waiting for incoming message - .....");
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(),true);
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null)
{
System.out.println ("Server: " + inputLine);
out.println(inputLine);
if (inputLine.equals("Bye."))
break;
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
}
I have tried to use Mule's TCP inbound endpoint as a server, but I am not able to see how I can identify a successful connection from the client, inorder to trigger the outbound message. The flow gets triggered only when a message is sent across from the client. Is there a way I can extend the functionality of the Mule TCP connector and have a listener which could do the above requirement?
Based on the answer provided, this is how I implemented this -
public class TCPMuleOut extends TcpMessageReceiver {
boolean InitConnection = false;
Socket clientSocket = null;
public TCPMuleOut(Connector connector, FlowConstruct flowConstruct,
InboundEndpoint endpoint) throws CreateException {
super(connector, flowConstruct, endpoint);
}
protected Work createWork(Socket socket) throws IOException {
return new MyTcpWorker(socket, this);
}
protected class MyTcpWorker extends TcpMessageReceiver.TcpWorker {
public MyTcpWorker(Socket socket, AbstractMessageReceiver receiver)
throws IOException {
super(socket, receiver);
// TODO Auto-generated constructor stub
}
#Override
protected Object getNextMessage(Object resource) throws Exception {
if (InitConnection == false) {
clientSocket = this.socket;
logger.debug("Sending logon message");
PrintStream pingStream = new PrintStream(
clientSocket.getOutputStream());
pingStream.print("Log on message");
pingStream.flush();
InitConnection = true;
}
long keepAliveTimeout = ((TcpConnector) connector)
.getKeepAliveTimeout();
Object readMsg = null;
try {
// Create a monitor if expiry was set
if (keepAliveTimeout > 0) {
((TcpConnector) connector).getKeepAliveMonitor()
.addExpirable(keepAliveTimeout,
TimeUnit.MILLISECONDS, this);
}
readMsg = protocol.read(dataIn);
// There was some action so we can clear the monitor
((TcpConnector) connector).getKeepAliveMonitor()
.removeExpirable(this);
if (dataIn.isStreaming()) {
}
return readMsg;
} catch (SocketTimeoutException e) {
((TcpConnector) connector).getKeepAliveMonitor()
.removeExpirable(this);
System.out.println("Socket timeout");
} finally {
if (readMsg == null) {
// Protocols can return a null object, which means we're
// done
// reading messages for now and can mark the stream for
// closing later.
// Also, exceptions can be thrown, in which case we're done
// reading.
dataIn.close();
InitConnection = false;
logger.debug("Client closed");
}
}
return null;
}
}
}
And the TCP connector is as below:
<tcp:connector name="TCP" doc:name="TCP connector"
clientSoTimeout="100000" receiveBacklog="0" receiveBufferSize="0"
sendBufferSize="0" serverSoTimeout="100000" socketSoLinger="0"
validateConnections="true" keepAlive="true">
<receiver-threading-profile
maxThreadsActive="5" maxThreadsIdle="5" />
<reconnect-forever />
<service-overrides messageReceiver="TCPMuleOut" />
<tcp:direct-protocol payloadOnly="true" />
</tcp:connector>
What you're trying to do is a little difficult to accomplish but not impossible. The messages are received by the org.mule.transport.tcp.TcpMessageReceiver class, and this class always consumes the data in the input stream to create the message that injects in the flow.
However, you could extend that receiver and instruct the TCP module to use yours by adding a service-overrides tag in your flow's tcp connector (documented here) and replacing the messageReceiver element.
In your extended receiver you should change the TcpWorker.getNextMessage method in order to send the ack message before read from the input stream.
HTH, Marcos.

ActiveMQ fail-over of producer and consumer with a shared directory doesn't happen

We have two ActiveMQ(version 5.10.0) instances running and I am using the shared storage to achieve HA.
However I am unable to see failover happening for the producer and consumer(s).
ActiveMQ broker-1 runs on IP1 and broker-2 on IP2
And under the activemq.xml of configuration I have modified persistence adapter to use a shared directory which is present on IP1.
<persistenceAdapter>
<kahaDB directory="\\IP1\shared-directory\for activemq\data"/>
</persistenceAdapter>
Both in producer and consumer sides I am using following JNDI configurations to get the connections and build sessions,etc.
jndi.properties
java.naming.factory.initial = ..........ActiveMQInitialContextFactory
java.naming.provider.url = failover:(tcp://IP1:61616,tcp://IP2:61616)?randomize=false
connectionFactoryNames = myConnectionFactory
queue.requestQ = my.RequestQ
Interesting part is :
When I start this broker pair, I see that one of the brokers becomes master.
When I start the producer, which puts the message on the Q (say producer has put 100 messages on the Q). While my producer is still running; I shutdown master broker, hence slave broker acquires the file-lock and becomes master.When I open the webconsole I see that 100 messages are still there on the Q. Even though producer is running it no longer puts any messages on this Q.
Similar to this for the consumers also.
Consumer was picking messages from the Q, this Q has say 100 messages unconsumed when master failed, now master goes down, slave becomes master, I see 100 messages are still unconsumed, but the consumer does not pick any message from the Q.
I waited them to failover for a long time.(>10 mins.)
Can any one please suggest what configuration am I missing ?
I am copy pasting producer and consumer as is (I've copied this from ActiveMQ in action book with minor modifications).
Producer
public class Producer {
private static String brokerURL = "failover:(tcp://IP1:3389,tcp://IP2:3389)";
private static transient ConnectionFactory factory;
private transient Connection connection;
private transient Session session;
private transient MessageProducer producer;
private static int count = 10;
private static int total;
private static int id = 1000000;
private String jobs[] = new String[] { "suspend", "delete" };
public Producer() throws JMSException {
factory = new ActiveMQConnectionFactory(brokerURL);
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(null);
}
public void close() throws JMSException {
if (connection != null) {
connection.close();
}
}
public static void main(String[] args) throws JMSException {
Producer producer = new Producer();
while (total < 1000) {
for (int i = 0; i < count; i++) {
producer.sendMessage();
}
total += count;
System.out.println("Sent '" + count + "' of '" + total
+ "' job messages");
try {
Thread.sleep(1000);
} catch (InterruptedException x) {
}
}
producer.close();
}
public void sendMessage() throws JMSException {
int idx = 0;
while (true) {
idx = (int) Math.round(jobs.length * Math.random());
if (idx < jobs.length) {
break;
}
}
String job = jobs[idx];
Destination destination = session.createQueue("JOBS." + job);
Message message = session.createObjectMessage(id++);
System.out.println("Sending: id: "
+ ((ObjectMessage) message).getObject() + " on queue: "
+ destination);
producer.send(destination, message);
}
}
Consumer
public class Consumer {
private static String brokerURL = "failover:(tcp://IP1:3389,tcp://IP2:3389)";
private static transient ConnectionFactory factory;
private transient Connection connection;
private transient Session session;
private String jobs[] = new String[] { "suspend", "delete" };
public Consumer() throws JMSException {
factory = new ActiveMQConnectionFactory(brokerURL);
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
}
public void close() throws JMSException {
if (connection != null) {
connection.close();
}
}
public static void main(String[] args) throws JMSException {
Consumer consumer = new Consumer();
for (String job : consumer.jobs) {
Destination destination = consumer.getSession().createQueue(
"JOBS." + job);
MessageConsumer messageConsumer = consumer.getSession()
.createConsumer(destination);
messageConsumer.setMessageListener(new Listener(job));
}
}
public Session getSession() {
return session;
}
}
Just one more thing:
I am more interested in consumer failover than producer.
One more observation is : Consumer stops and comes to the command prompt abruptly.
Thank you.
-JE

What is the magic behind the scene of Java ee jms?

I've just started with Java ee 7, and here is something I couldnt get the idea of how it magically works.
I follow the example from the book Beginning Java EE 7 by Antonio Goncalves. I managed to compile and deploye the code of chapter 13 (about JMS) without any problem. Messages are sent and received as expected, but that make me confused.
The source code is composite of a consumer class, a producer class, a POJO and a MDB class.
here is the consumer:
public class OrderConsumer {
public static void main(String[] args) throws NamingException {
// Gets the JNDI context
Context jndiContext = new InitialContext();
// Looks up the administered objects
ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/javaee7/ConnectionFactory");
Destination topic = (Destination) jndiContext.lookup("jms/javaee7/Topic");
// Loops to receive the messages
System.out.println("\nInfinite loop. Waiting for a message...");
try (JMSContext jmsContext = connectionFactory.createContext()) {
while (true) {
OrderDTO order = jmsContext.createConsumer(topic).receiveBody(OrderDTO.class);
System.out.println("Order received: " + order);
}
}
}
}
the producer:
public class OrderProducer {
public static void main(String[] args) throws NamingException {
if (args.length != 1) {
System.out.println("usage : enter an amount");
System.exit(0);
}
System.out.println("Sending message with amount = " + args[0]);
// Creates an orderDto with a total amount parameter
Float totalAmount = Float.valueOf(args[0]);
OrderDTO order = new OrderDTO(1234l, new Date(), "Serge Gainsbourg", totalAmount);
// Gets the JNDI context
Context jndiContext = new InitialContext();
// Looks up the administered objects
ConnectionFactory connectionFactory = (ConnectionFactory) jndiContext.lookup("jms/javaee7/ConnectionFactory");
Destination topic = (Destination) jndiContext.lookup("jms/javaee7/Topic");
try (JMSContext jmsContext = connectionFactory.createContext()) {
// Sends an object message to the topic
jmsContext.createProducer().setProperty("orderAmount", totalAmount).send(topic, order);
System.out.println("\nOrder sent : " + order.toString());
}
}
}
the MDB :
#MessageDriven(mappedName = "jms/javaee7/Topic", activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "messageSelector", propertyValue = "orderAmount > 1000")
})
public class ExpensiveOrderMDB implements MessageListener {
public void onMessage(Message message) {
try {
OrderDTO order = message.getBody(OrderDTO.class);
System.out.println("Expensive order received: " + order.toString());
} catch (JMSException e) {
e.printStackTrace();
}
}
}
Content of msg encapsulated in a POJO object which implements Serializable interface
ExpensiveOrderMDB and the POJO is packaged in a .jar file and deploy in glassfish server running locally. Connection and desitination resouces are created by asadmin.
Question is: How can the consumer and producer know that the connection and destination are available on local glassfish server for it to make a connection and send/receive msg? (The lines that create connection and destination say nothing about local glassfish server)
Probably there is a jndi.properties file in which the connection to the glassfish is defined

JGroups not forming a cluster with UDP

I am trying to create a leader election protocol using JGroups so that N instances of my program can elect a master and all clients get the ip of this master.
More or less the current implementation relies on each instance trying to acquire a lock on lock-channel and when it successfully acquires this channel it becomes master and all others switch to clients.
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.*;
import org.jgroups.*;
import org.jgroups.blocks.locking.LockService;
public class AutoDiscovery
{
static org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(AutoDiscovery.class); //used for logging purposes (see log4j library)
/* this variable indicates whether I have become the master or I'm just a client*/
public volatile AtomicBoolean becomeMaster = new AtomicBoolean(false);
/* The address of the server if we are a client or of ourself if we are
* server */
public String serverAddress;
/* A channel on which to acquire a lock, so that only one can become server */
private JChannel lockChannel;
/* A shared channel ffor communication between client and master*/
private JChannel communicationChannel;
private LockService lockService;
/* A thread which tries to acquire a lock */
private Thread acquiringThread;
/* A thread which listens for the server ip which may change */
private Thread listeningThread;
/* A thread which lists the status and initializes the acquiring thread*/
private Thread statusThread;
private String name;
/* If we pass from being a client to being a server we must stop the listening
* thread however we cannot call listeningThread.stop() but instead we change
* the stopListening boolean to true */
private boolean stopListening = false;
/* This lock communicates I have finally become either master or client so
* the serverAddress and becomeMaster variables are correctly set */
public final Object finishedLock = new Object();
public static void main(String[] args) throws Exception
{
Thread.currentThread().setName("MyMainThread");
Random rand = new Random();
AutoDiscovery master = new AutoDiscovery("Node" + rand.nextInt(10));
master.lockChannel = new JChannel(AutoDiscovery.class.getResource("/resource/udp.xml"));
master.lockChannel.connect("lock-channel");
master.communicationChannel = new JChannel(AutoDiscovery.class.getResource("/resource/udp.xml"));
master.communicationChannel.connect("communication-channel");
master.lockService = new LockService(master.lockChannel);
master.startStatusPrinterThread();
}
public AutoDiscovery(String name)
{
this.name = name;
}
public AutoDiscovery()
{
try
{
Thread.currentThread().setName("MyMainThread");
Random rand = new Random();
this.name = ("Node" + rand.nextInt(10));
lockChannel = new JChannel(AutoDiscovery.class.getResource("/resource/udp.xml"));
lockChannel.connect("lock-channel");
communicationChannel = new JChannel(AutoDiscovery.class.getResource("/resource/udp.xml"));
communicationChannel.connect("communication-channel");
lockService = new LockService(lockChannel);
startStatusPrinterThread();
}
catch (Exception ex)
{
Logger.getLogger(AutoDiscovery.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void startAcquiringThread()
{
acquiringThread = new Thread()
{
#Override
public void run()
{
while (true)
{
//if you have become Master send your ip every now and then
if (becomeMaster.get())
{
try
{
communicationChannel.send(new Message(null, null, "serverip " + serverAddress));
}
catch (Exception ex)
{
Logger.getLogger(AutoDiscovery.class.getName()).log(Level.SEVERE, null, ex);
}
}
else
{
try
{
Thread.currentThread().setName(name + "AcquiringThread");
Lock lock = lockService.getLock("serverLock");
if (lock.tryLock(4, TimeUnit.SECONDS))
{
becomeMaster.set(true);
stopListening = true;
/* Now that I'm server I must find out my own ip address on which to listen */
Enumeration<NetworkInterface> networkInterfaces;
try
{
networkInterfaces = NetworkInterface.getNetworkInterfaces();
for (NetworkInterface netint : Collections.list(networkInterfaces))
{
Enumeration<InetAddress> inetAddresses = netint.getInetAddresses();
for (InetAddress inetAddress : Collections.list(inetAddresses))
{
if (isIPAddress(inetAddress.getHostAddress())
&& !inetAddress.getHostAddress().equals("127.0.0.1"))
{
serverAddress = inetAddress.getHostAddress();
}
}
}
/* I notify to the rest of the program I have correctly initialized
* becomeMaster and serverAddress */
synchronized (finishedLock)
{
finishedLock.notify();
}
}
catch (Exception e)
{
Logger.getLogger(AutoDiscovery.class.getName()).log(Level.SEVERE, null, e);
System.exit(0);
}
log.info(Thread.currentThread().getName() + ": I acquired lock! will become master! my ip is " + serverAddress);
}
else
{
becomeMaster.set(false);
stopListening = false;
if (listeningThread == null || !listeningThread.isAlive())
{
if (!stopListening) //??? this codnition might be useless
{
startListeningThread();
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
try
{
sleep(5000L);
}
catch (InterruptedException ex)
{
Logger.getLogger(AutoDiscovery.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
};
acquiringThread.setDaemon(true);
acquiringThread.start();
}
public void startListeningThread()
{
listeningThread = new Thread()
{
#Override
public void run()
{
try
{
while (true)
{
Thread.currentThread().setName(name + "ListeningThread");
communicationChannel.setReceiver(new ReceiverAdapter()
{
#Override
public void receive(Message msg)
{
if (msg.getObject() != null)
{
String leaderServerAddress = (msg.getObject().toString().substring(9));
if (isIPAddress(leaderServerAddress))
{
serverAddress = leaderServerAddress;
log.info(name + " Master server has ip" + serverAddress);
/* I notify to the rest of the program I have correctly initialized
* becomeMaster and serverAddress */
synchronized (finishedLock)
{
finishedLock.notify();
}
}
else
{
log.info(name + ": discarded message " + msg.getObject().toString());
}
}
}
});
sleep(10000L);
if (stopListening)
{
return;
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
};
listeningThread.setDaemon(true);
listeningThread.start();
}
private void startStatusPrinterThread()
{
statusThread = new Thread()
{
#Override
public void run()
{
Thread.currentThread().setName(name + "StatusPrinterThread");
startAcquiringThread();
while (true)
{
try
{
if (becomeMaster.get())
{
log.info(name + " startStatusPrinterThread(): I am happily a Master!");
}
else
{
if (!acquiringThread.isAlive())
{
startAcquiringThread();
}
}
sleep(5000L);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
};
statusThread.setDaemon(true);
statusThread.start();
}
private static boolean isIPAddress(String str)
{
Pattern ipPattern = Pattern.compile("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
return ipPattern.matcher(str).matches();
}
}
now my current udp.xml is
<config xmlns="urn:org:jgroups"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="urn:org:jgroups http://www.jgroups.org/schema/JGroups-3.0.xsd">
<UDP
mcast_port="${jgroups.udp.mcast_port:45588}"
tos="8"
ucast_recv_buf_size="20M"
ucast_send_buf_size="640K"
mcast_recv_buf_size="25M"
mcast_send_buf_size="640K"
loopback="true"
level="WARN"
log_discard_msgs="false"
max_bundle_size="64K"
max_bundle_timeout="30"
ip_ttl="${jgroups.udp.ip_ttl:8}"
enable_diagnostics="true"
thread_naming_pattern="cl"
timer_type="new"
timer.min_threads="4"
timer.max_threads="10"
timer.keep_alive_time="3000"
timer.queue_max_size="500"
thread_pool.enabled="true"
thread_pool.min_threads="2"
thread_pool.max_threads="8"
thread_pool.keep_alive_time="5000"
thread_pool.queue_enabled="true"
thread_pool.queue_max_size="10000"
thread_pool.rejection_policy="discard"
oob_thread_pool.enabled="true"
oob_thread_pool.min_threads="1"
oob_thread_pool.max_threads="8"
oob_thread_pool.keep_alive_time="5000"
oob_thread_pool.queue_enabled="false"
oob_thread_pool.queue_max_size="100"
oob_thread_pool.rejection_policy="Run"/>
<PING timeout="2000"
num_initial_members="3"/>
<MERGE2 max_interval="30000"
min_interval="10000"/>
<FD_SOCK/>
<FD_ALL/>
<VERIFY_SUSPECT timeout="1500" />
<BARRIER />
<pbcast.NAKACK exponential_backoff="300"
xmit_stagger_timeout="200"
use_mcast_xmit="false"
discard_delivered_msgs="true"/>
<UNICAST />
<pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
max_bytes="4M"/>
<pbcast.GMS print_local_addr="true" join_timeout="3000"
view_bundling="true"/>
<UFC max_credits="2M"
min_threshold="0.4"/>
<MFC max_credits="2M"
min_threshold="0.4"/>
<FRAG2 frag_size="60K" />
<pbcast.STATE_TRANSFER />
<CENTRAL_LOCK />
<!-- pbcast.FLUSH /-->
</config>
Now the above works when I run N instances of the program on the same machine (with N-1 members becoming client and 1 becoming master).
When run on two different machines both connected to the same LAN, apparently after calling JChannel.connect() with the same clustername in each member, each member creates its channel and no common cluster is created. The result is that when sending messages to the clients the other master sees a different physical address for the same cluster name and all messages are dropped.
So I get warnings like:
7683 [Incoming-1,communication-channel,pc-home-41714] WARN org.jgroups.protocols.pbcast.NAKACK - [JGRP00011] pc-home-41714: dropped message 293 from non-member cf8b4ea6-8cc8-cb21-538f-b03f3fa7413d (view=[pc-home-41714|0] [pc-home-41714])
1207996 [TransferQueueBundler,communication-channel,pc-home-5280] WARN org.jgroups.protocols.UDP - pc-home-5280: no physical address for cf8b4ea6-8cc8-cb21-538f-b03f3fa7413d, dropping message
1209526 [TransferQueueBundler,lock-channel,pc-home-59082] WARN org.jgroups.protocols.UDP - pc-home-59082: no physical address for efbe6408-0e21-d119-e2b8-f1d5762d9b45, dropping message
If I change udp.xml loopback="true" to loopback="false" what happens is that they both connect to the same cluster but then they give an error like:
55539 [Node0StatusPrinterThread] INFO plarz.net.planningig.autodiscovery.AutoDiscovery - Node0 startStatusPrinterThread(): I am happily a Master!
59077 [TransferQueueBundler,lock-channel,pc-test-6919] ERROR org.jgroups.protocols.UDP - pc-test-6919: exception sending bundled msgs: java.lang.Exception: dest=/fe80:0:0:0:226:18ff:fece:6ccc%2:43109 (130 bytes):, cause: java.io.IOException: Network is unreachable
59505 [TransferQueueBundler,communication-channel,pc-test-35303] ERROR org.jgroups.protocols.UDP - pc-test-35303: exception sending bundled msgs: java.lang.Exception: dest=/fe80:0:0:0:226:18ff:fece:6ccc%2:55053 (139 bytes):, cause: java.io.IOException: Network is unreachable
Error:
[Server:ha-server-3] 13:59:13,122 WARNING [org.jgroups.protocols.UDP]
(OOB-15,null) null: no physical address for
766de5c9-8ac2-6d30-89ef-78d39aa5f7eb, dropping message
In My case, it was due to having multiple jboss clusters at a same
network and each of the clusters were having same name. For example
ha-server-1 and ha-server-2 existed at two different clusters in
different machines.
Cluster-1(10.10.10.10): |
+- ha-server-1
+- ha-server-2
Cluster-2(10.10.10.20): |
+- ha-server-1
+- ha-server-2
I have resolved this problem by changing the ha-server names. Note:
Both were independent cluster. I assume it happened due to the
multicast issue of JGroups. Any further explanation from an expert
like you will be nice.
refer to http://icfun.blogspot.com/2013/10/no-physical-address-for-766de5c9-8ac2.html

ActiveMQ and JMS : Basic steps for novice

Hi all please give some basic about ActiveMQ with JMS for novice. And configuration steps also.
We are going to create a console based application using multithreading. So create an java project for console application.
Now follow these steps..........
Add javax.jms.jar, activemq-all-5.3.0.jar, log4j-1.2.15.jar to your project library.
(You can download all of above jar files from http://www.jarfinder.com/ .
create a file naming jndi.properties and paste these following texts .. ( Deatils for jndi.properties just Google it)
# START SNIPPET: jndi
java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory
# use the following property to configure the default connector
java.naming.provider.url = tcp://localhost:61616
# use the following property to specify the JNDI name the connection factory
# should appear as.
#connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry
connectionFactoryNames = connectionFactory, queueConnectionFactory, topicConnectionFactry
# register some queues in JNDI using the form
# queue.[jndiName] = [physicalName]
queue.MyQueue = example.MyQueue
# register some topics in JNDI using the form
# topic.[jndiName] = [physicalName]
topic.MyTopic = example.MyTopic
# END SNIPPET: jndi
Add JMSConsumer.java
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JMSConsumer implements Runnable{
private static final Log LOG = LogFactory.getLog(JMSConsumer.class);
public void run() {
Context jndiContext = null;
ConnectionFactory connectionFactory = null;
Connection connection = null;
Session session = null;
MessageConsumer consumer = null;
Destination destination = null;
String sourceName = null;
final int numMsgs;
sourceName= "MyQueue";
numMsgs = 1;
LOG.info("Source name is " + sourceName);
/*
* Create a JNDI API InitialContext object
*/
try {
jndiContext = new InitialContext();
} catch (NamingException e) {
LOG.info("Could not create JNDI API context: " + e.toString());
System.exit(1);
}
/*
* Look up connection factory and destination.
*/
try {
connectionFactory = (ConnectionFactory)jndiContext.lookup("queueConnectionFactory");
destination = (Destination)jndiContext.lookup(sourceName);
} catch (NamingException e) {
LOG.info("JNDI API lookup failed: " + e);
System.exit(1);
}
try {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
consumer = session.createConsumer(destination);
connection.start();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
MessageListener listener = new MyQueueMessageListener();
consumer.setMessageListener(listener );
//Let the thread run for some time so that the Consumer has suffcient time to consume the message
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (JMSException e) {
LOG.info("Exception occurred: " + e);
} finally {
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
}
}
}
}
}
Add JMSProducer.java
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class JMSProducer implements Runnable{
private static final Log LOG = LogFactory.getLog(JMSProducer.class);
public JMSProducer() {
}
//Run method implemented to run this as a thread.
public void run(){
Context jndiContext = null;
ConnectionFactory connectionFactory = null;
Connection connection = null;
Session session = null;
Destination destination = null;
MessageProducer producer = null;
String destinationName = null;
final int numMsgs;
destinationName = "MyQueue";
numMsgs = 5;
LOG.info("Destination name is " + destinationName);
/*
* Create a JNDI API InitialContext object
*/
try {
jndiContext = new InitialContext();
} catch (NamingException e) {
LOG.info("Could not create JNDI API context: " + e.toString());
System.exit(1);
}
/*
* Look up connection factory and destination.
*/
try {
connectionFactory = (ConnectionFactory)jndiContext.lookup("queueConnectionFactory");
destination = (Destination)jndiContext.lookup(destinationName);
} catch (NamingException e) {
LOG.info("JNDI API lookup failed: " + e);
System.exit(1);
}
/*
* Create connection. Create session from connection; false means
* session is not transacted.create producer, set the text message, set the co-relation id and send the message.
*/
try {
connection = connectionFactory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
TextMessage message = session.createTextMessage();
for (int i = 0; i
Add MyQueueMessageListener.java
import java.io.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.jms.*;
public class MyQueueMessageListener implements MessageListener {
private static final Log LOG = LogFactory.getLog(MyQueueMessageListener.class);
/**
*
*/
public MyQueueMessageListener() {
// TODO Auto-generated constructor stub
}
/** (non-Javadoc)
* #see javax.jms.MessageListener#onMessage(javax.jms.Message)
* This is called on receving of a text message.
*/
public void onMessage(Message arg0) {
LOG.info("onMessage() called!");
if(arg0 instanceof TextMessage){
try {
//Print it out
System.out.println("Recieved message in listener: " + ((TextMessage)arg0).getText());
System.out.println("Co-Rel Id: " + ((TextMessage)arg0).getJMSCorrelationID());
try {
//Log it to a file
BufferedWriter outFile = new BufferedWriter(new FileWriter("MyQueueConsumer.txt"));
outFile.write("Recieved message in listener: " + ((TextMessage)arg0).getText());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
System.out.println("~~~~Listener : Error in message format~~~~");
}
}
}
Add SimpleApp.java
public class SimpleApp {
//Run the producer first, then the consumer
public static void main(String[] args) throws Exception {
runInNewthread(new JMSProducer());
runInNewthread(new JMSConsumer());
}
public static void runInNewthread(Runnable runnable) {
Thread brokerThread = new Thread(runnable);
brokerThread.setDaemon(false);
brokerThread.start();
}
}
Now run SimpleApp.java class.
All da best. Happy coding.
Here it is a simple junit test for ActiveMQ and Apache Camel. This two technologies works very good together.
If you want more details about the code, you can find a post in my blog:
http://ignaciosuay.com/unit-testing-active-mq/
public class ActiveMQTest extends CamelTestSupport {
#Override
protected CamelContext createCamelContext() throws Exception {
CamelContext camelContext = super.createCamelContext();
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");
camelContext.addComponent("activemq", jmsComponentClientAcknowledge(connectionFactory));
return camelContext;
}
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("mina:tcp://localhost:6666?textline=true&sync=false")
.to("activemq:processHL7");
from("activemq:processHL7")
.to("mock:end");
}
};
}
#Test
public void testSendHL7Message() throws Exception {
MockEndpoint mock = getMockEndpoint("mock:end");
String m = "MSH|^~\\&|hl7Integration|hl7Integration|||||ADT^A01|||2.5|\r" +
"EVN|A01|20130617154644\r" +
"PID|1|465 306 5961||407623|Wood^Patrick^^^MR||19700101|1|\r" +
"PV1|1||Location||||||||||||||||261938_6_201306171546|||||||||||||||||||||||||20130617134644|";
mock.expectedBodiesReceived(m);
template.sendBody("mina:tcp://localhost:6666?textline=true&sync=false", m);
mock.assertIsSatisfied();
}