Producer count in the activemq web console shows 0 all the time, even if there are producers connected to the broker. I'm not sure why?
My producer code looks like this.
public boolean postMessage(List<? extends JMSMessageBean> messageList, String data, int messageCount)
throws JMSException {
String queueName = null;
MessageProducer producer = null;
Connection connection = null;
Session session = null;
try {
connection = pooledConnectionFactory.createConnection();
connection.setExceptionListener(this);
connection.start();
session = connection.createSession(false, Session.CLIENT_ACKNOWLEDGE);
int index = 0;
for (JMSMessageBean message : messageList) {
if (producer == null || !message.getQueueName().equals(queueName)) {
queueName = message.getQueueName();
producer = getQueueProducer(queueName, session);
}
Message _omessage = session.createObjectMessage(message);
_omessage.setStringProperty("MESSAGE_INDEX", messageCount + ":" + index);
_omessage.setIntProperty("RETRY_COUNT", 0);
_omessage.setJMSType(message.getJmsType());
if (data != null) {
_omessage.setStringProperty("RAW_DATA", data);
}
producer.send(_omessage);
index++;
}
} catch (JMSException e) {
logger.error("Exception while creating connection to jms broker", e);
} finally {
try {
if (null != session) {
session.close();
}
if (null != connection) {
connection.close();
}
if(null != producer) {
producer.close();
}
} catch (JMSException e) {
logger.error(e.getMessage(), e);
}
}
return true;
}
Am using a pooledconnectionfactory to create sessions, connections, and messageproducers. Everytime, someone has to post a message, a new connection is requested from the pooledconnectionfactory. and then
The ActiveMQ client often uses what they call "dynamic producers"-- a producer per message for non-transacted sessions. If you walked the JMS object lifecycle, you'd find there is little need to keep a producer object around in a non-transacted session-- which is different from the consumer object.
Look under the dynamicProducers list in JMX, and you'll catch them being created. You can also monitor the advisory topics to see them get created and destroyed.
Side note: your object close order in the finally is incorrect.. you should close objects in reverse order-- producer, session, connection.
Related
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.
I'm new to JMS+OPenMq + Glassfish , please give me up by make successful send message and receive messages....
I have created two different servlet programs and i have deployed in galssfish server....Here i'm sending message successfully , but consumer has not able to consuming messages ......
producer :
Properties p = new Properties();
p.put("java.naming.factory.initial","com.sun.enterprise.naming.SerialInitContextFactory");
p.put("java.naming.factory.url.pkgs","com.sun.enterprise.naming");
p.put("java.naming.provider.url", "iiop://localhost:3700");
InitialContext jndiContext = new InitialContext(p);
TopicConnectionFactory connectionFactory = (TopicConnectionFactory) jndiContext.lookup("jms/HQTapicConnectionFactory");
Topic topic = (Topic) jndiContext.lookup("jms/HqDestTopic");
System.out.println(topic.getTopicName());
TopicConnection connection = (TopicConnection) connectionFactory.createTopicConnection();
System.out.println(connection.toString());
TopicSession session = connection.createTopicSession(true, Session.AUTO_ACKNOWLEDGE); //createSession(false, Session.AUTO_ACKNOWLEDGE);
TopicPublisher publisher = session.createPublisher(topic);
ObjectMessage message = session.createObjectMessage();
ArrayList<Employee> employeeList= new ArrayList<Employee>();
Employee employee = null;
for (int i = 0; i < 5; i++) {
employee = new Employee();
employee.setEmpid((100+i));
employee.setName("devid"+i);
employeeList.add(employee);
}
System.out.println(employeeList.size());
message.setObject(employeeList);
publisher.send(message);
Consumer:
public void onMessage(Message message){
ObjectMessage objectMessage= (ObjectMessage) message;
try{
System.out.println("Received the following message: ");
Object object = objectMessage.getObject();
if(object instanceof ArrayList){
ArrayList arrayList = (ArrayList)object;
for (int i = 0; i < arrayList.size(); i++) {
Object object1 = arrayList.get(i);
if(object1 instanceof Employee){
Employee employee = (Employee)object1;
System.out.println(employee.getEmpid());
System.out.println(employee.getName());
System.out.println();
}
}
}
}
catch (JMSException e)
{
e.printStackTrace();
}
}
I'm not able to receiving messages ,
Please help me to proper configure for broker in glassfish server.
,...appreciate for your replay
If your consumer is in a servlet, it will only catch the messages which are sent in the same moment of time (quite unlikely) - you are using topics which do not buffer by default.
Either use queues (instead of topics) or write a stand-alone program which is permanently running (and thus listening/eceiving). Normally topic listeners do not make much sense in a servlet.
I am using ActiveMQ in my app. My question is how to delete messages that ı consumed successfully from kahadb. Because if it is not deleted, my db.data file is growing up constantly.
Here is my consumer;
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:8182");
Connection connection = connectionFactory.createConnection();
connection.start();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
Destination destination = session.createQueue("TEST.FOO");
MessageConsumer consumer = session.createConsumer(destination);
MessageListener listner = new MessageListener() {
int count = 0;
public void onMessage(Message message) {
if (message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage) message;
ResponseDuration responseDuration = null;
try {
responseDuration = (ResponseDuration) objectMessage.getObject();
System.out.println("Received Time : " + new Date() + "Received: " + responseDuration.toString());
} catch (JMSException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
ResponseDurationOperations.insertResponseDurations(responseDuration);
count++;
System.out.println("Count = " + count);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
consumer.setMessageListener(listner);
Seems that ActiveMQ has a different meaning for what it means with persistance than you (and me as well).
Persistence is defined not to persist for ever but just to make you safe from message loss when you restart the server. See this
One option for you could be to switch off the persistence. See here.
For example by this way:
ActiveMQConnectionFactory("vm://localhost?broker.persistent=false");
I am learning to implement active mq interface in my project. This is how I am creating producers and consumers.
public void connectionSetup(String portName) { // portname is object of PortTO class. We are creating producer and consumer pair for every existing PortTO object.
Connection connection = null;
try {
if (timeToLive != 0) {
}
// Create the connection.
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory(user, password, url);
connection = connectionFactory.createConnection();
connection.start();
connection.setExceptionListener(this);
// Create the session
Session session = connection.createSession(transacted, Session.AUTO_ACKNOWLEDGE);
if (topic) {
destination = session.createTopic(subject);
} else {
destination = session.createQueue(portName);
}
// Create the producer.
MessageProducer producer = session.createProducer(destination); if (persistent) {
producer.setDeliveryMode(DeliveryMode.PERSISTENT);
} else {
producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
}
MessageConsumer consumer = session.createConsumer(destination); if (timeToLive != 0)
producer.setTimeToLive(timeToLive);
mapOfSession.put(portName, session);
mapOfMessageProducer.put(portName, producer);
mapOfMessageConsumer.put(portName, consumer); log.info("Producer is " + producer);
log.info("Consumer is " + consumer);
} catch (Exception e) {
log.error(e.getMessage());
}
}
So, we are creating producer and consumer and storing them in a map for every PortTO object. Now, producer is sending messages:
TextMessage message = session.createTextMessage();
message.setIntProperty(key, 2);
producer.send(message);
But consumer is not consuming it...
public void onMessage(Message message) {
PortService portService = new PortService();
List<PortTO> portTOList = portService.getMoxaPorts();
for(PortTO portTO : portTOList) { // catching messages from producers of every PortTO object
MessageConsumer consumer = DataCollectionMessageProducer.getMapOfMessageConsumer().get(portTO.getPort()); // getting consumer from map of PortTO
consumer.setMessageListener(this);
message = consumer.receive(1000); if (message instanceof TextMessage) {
/ / some processing
}
} else {
if (verbose) {
}
}
}
}
What can be the reason? Is my approach wrong ??
You are setting the messageListener in the onMessage method. This is a catch 22, since the onMessage method gets invoked only if the messageListener is set to that object.
Another thing, I am not sure why you would do a receive in a message listener. The onMessage will be invoked for each message on the queue once it has been set as listener and the logic for each received message should reside in there in an event driven fashion. At least, that is the idea with JMS in the first place
I'm running through a Glassfish web process and I need a non-container managed class (EJBUserManager) to be able to receive messages from a MessageDrivenBean. The class has the javax.jms.Queues and connection factories and I can write to the Queues. The queue sends to a MessageDrivenBean (AccountValidatorBean) that receives the code correctly, and then writes back a message. But the EJBUserManager attempts to read from the queue and never receives the message.
#Override
public boolean doesExist(String username) throws FtpException {
LOGGER.finer(String.format("Query if username %s exists", username));
QueueConnection queueConnection = null;
boolean doesExist = false;
try {
queueConnection = connectionFactory.createQueueConnection();
final UserManagerMessage userManagerMessage =
new UserManagerMessage(UserManagerQueryCommands.VALIDATE_USER, username);
final Session session = queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
final ObjectMessage objectMessage = session.createObjectMessage(userManagerMessage);
session.createProducer(accountValidatorQueue).send(objectMessage);
session.close();
queueConnection.close();
queueConnection = connectionFactory.createQueueConnection();
final QueueSession queueSession =
queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
LOGGER.finest(String.format("Right before doesExist receive for username %s", username));
final Message firstAttemptMessage = queueSession.createConsumer(userManagerQueue).receive(3000);
final Message message = firstAttemptMessage != null ?
firstAttemptMessage : queueSession.createConsumer(userManagerQueue).receiveNoWait();
LOGGER.finest(String.format("Right after doesExist receive for username %s", username));
LOGGER.finest(String.format("Is the message null: %b", message != null));
if (message != null && message instanceof StreamMessage) {
final StreamMessage streamMessage = (StreamMessage) message;
doesExist = streamMessage.readBoolean();
}
} catch (JMSException e) {
e.printStackTrace();
} finally {
if (queueConnection != null) {
try {
queueConnection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
}
return doesExist;
}
The above is the code from the EJBUserManager. Now, it can send to the accountValidatorQueue. It just never receives from the userManagerQueue
Here's the code for the AccountValidatorBean
private void validateUser(final String username) {
QueueConnection queueConnection = null;
final String doctype = doctypeLookupDAO.getDocumentTypeForUsername(username);
LOGGER.finest(String.format("Doctype %s for username %s", doctype, username));
try {
queueConnection = queueConnectionFactory.createQueueConnection();
final Session session = queueConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//final StreamMessage message = session.createStreamMessage();
//message.clearBody();
//message.writeBoolean(doctype != null);
//message.reset();
final ObjectMessage message = session.createObjectMessage(Boolean.valueOf(doctype != null));
final MessageProducer messageProducer =
session.createProducer(userManagerQueue);
LOGGER.finest(String.format("Queue name %s of producing queue", userManagerQueue.getQueueName()));
messageProducer.send(message);
LOGGER.finest(String.format("Sending user validate message for user %s", username));
messageProducer.close();
session.close();
} catch (JMSException e) {
e.printStackTrace();
} finally {
if (queueConnection != null) {
try {
queueConnection.close();
} catch (JMSException e1) {
e1.printStackTrace();
}
}
}
}
Fixed. I needed to call QueueConnection.start() to consume messages from the queue.