I am new to JMS, after a long re search i googled out a code to connect to JMS and post a msg.
The problem is i need to post the message in a remote queue, But i am not sure how to establish connection to it and post the message.
SERVER TYPE : TIBCO EMS
SERVER HOST : **.*****.net
PORT : *
**USername : user
passsword : user123
Queue : *.*....Order.Management..1
I would like to establish connection, post a simple msg and retrieve it back.
Kindly help! thanks in advance
CODE WHICH I GOT FROM INTERNET
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Hashtable;
import javax.jms.*;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class emm {
// Defines the JNDI context factory.
public final static String JNDI_FACTORY="com.tibco.tibjms.naming.TibjmsInitialContextFactory";
// Defines the JMS context factory.
public final static String JMS_FACTORY="jms/TestConnectionFactory";
// Defines the queue.
public final static String QUEUE="CPW.GBR.POR.Public.Request.Order.Management.UpdateProvisioningStatus.1";
private QueueConnectionFactory qconFactory;
private ConnectionFactory conFactory;
private QueueConnection qcon;
private QueueSession qsession;
private QueueSender qsender;
private Queue queue;
private TextMessage msg;
/**
* Creates all the necessary objects for sending
* messages to a JMS queue.
*
* #param ctx JNDI initial context
* #param queueName name of queue
* #exception NamingException if operation cannot be performed
* #exception JMSException if JMS fails to initialize due to internal error
*/
public void init(Context ctx, String queueName)
throws NamingException, JMSException
{
qconFactory = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
qcon = qconFactory.createQueueConnection();
qsession = qcon.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
queue = (Queue) ctx.lookup(queueName);
qsender = qsession.createSender(queue);
msg = qsession.createTextMessage();
qcon.start();
}
/**
* Sends a message to a JMS queue.
*
* #param message message to be sent
* #exception JMSException if JMS fails to send message due to internal error
*/
public void send(String message) throws JMSException {
msg.setText(message);
qsender.send(msg);
}
/**
* Closes JMS objects.
* #exception JMSException if JMS fails to close objects due to internal error
*/
public void close() throws JMSException {
qsender.close();
qsession.close();
qcon.close();
}
/** main() method.
*
* #param args WebLogic Server URL
* #exception Exception if operation fails
*/
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.out.println("Usage: java examples.jms.queue.QueueSend WebLogicURL");
return;
}
InitialContext ic = getInitialContext(args[0]);
emm qs = new emm();
qs.init(ic, QUEUE);
readAndSend(qs);
qs.close();
}
private static void readAndSend(emm qs)
throws IOException, JMSException
{
BufferedReader msgStream = new BufferedReader(new InputStreamReader(System.in));
String line=null;
boolean quitNow = false;
do {
System.out.print("Enter message (\"quit\" to quit): \n");
line = msgStream.readLine();
if (line != null && line.trim().length() != 0) {
qs.send(line);
System.out.println("JMS Message Sent: "+line+"\n");
quitNow = line.equalsIgnoreCase("quit");
}
} while (! quitNow);
}
private static InitialContext getInitialContext(String url)
throws NamingException
{
Hashtable env = new Hashtable();
env.put(Context.INITIAL_CONTEXT_FACTORY, JNDI_FACTORY);
env.put(Context.PROVIDER_URL, url);
return new InitialContext(env);
}
}
Finally from different sources i found the best possible to way for this.
This code will definitely work. I have tried this out and is running currently on my machine
import java.util.Properties;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueReceiver;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.*;
public class JMSExample {
static String serverUrl = "tcp://10.101.111.101:10001"; // values changed
static String userName = "user";
static String password = "pwd";
static QueueConnection connection;
static QueueReceiver queueReceiver;
static Queue queue;
static TextMessage message;
public static void sendTopicMessage(String topicName, String messageStr) {
Connection connection = null;
Session session = null;
MessageProducer msgProducer = null;
Destination destination = null;
try {
TextMessage msg;
System.out.println("Publishing to destination '" + topicName
+ "'\n");
ConnectionFactory factory = new com.tibco.tibjms.TibjmsConnectionFactory(
serverUrl);
connection = factory.createConnection(userName, password);
session = connection.createSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue(topicName);
msgProducer = session.createProducer(null);
msg = session.createTextMessage();
msg.setStringProperty("SourceId", userName);
msg.setStringProperty("BusinessEvent", password);
msg.setText(messageStr);
msgProducer.send(destination, msg);
System.out.println("Published message: " + messageStr);
connection.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws JMSException {
// TODO Auto-generated method stub
JMSExample.sendTopicMessage("***.***.***.**.**.Order.Management.***.1",
"Hi");
//System.out.println(getMessage());
}
As i mentioned some code for inspiration (SLIGHTLY improved your code. Not something i would want to see in production!)
// Use the domain-agnostic API
private Connection connection;ery
private Session session;
private MessageProducer producer;
private Queue queue;
public void init(Context ctx, String queueName) {
try {
ConnectionFactory cnf = (QueueConnectionFactory) ctx.lookup(JMS_FACTORY);
queue = (Queue) ctx.lookup(queueName);
connection = cnf.createConnection("user", "user123");
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(queue);
connection.start();
} catch (NamingException e) {
throw new RuntimeException(e);
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
And make your send like this (don't reuse the same Message object, but create a new one for each message you are sending)
public void send(String message) throws JMSException {
TextMessage msg = session.createTextMessage();
msg.setText(message);
producer.send(msg);
}
Put a try..finally around the code in your main method:
try {
readAndSend(qs);
} finally {
qs.close();
}
The code you are using is not very good (understatement). It is programmed too brittle for a production system. You should not use state the way this program does.
Also there is no need to use the domain specific JMS API. You can use the domain (queue/topic) agnostic one.
When you run the program pass in the JNDI URL for your TIBCO server.
Related
I'm a newbie in IBM MQ (https://www.ibm.com/cloud-computing/products/cloud-integration/mq-trial/index.html)
I'd like to know if I could send and get messages from IBM MQ using some code like this:
/*
* Sample program
* © COPYRIGHT International Business Machines Corp. 2009
* All Rights Reserved * Licensed Materials - Property of IBM
*
* This sample program is provided AS IS and may be used, executed,
* copied and modified without royalty payment by customer
*
* (a) for its own instruction and study,
* (b) in order to develop applications designed to run with an IBM
* WebSphere product for the customer's own internal use.
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.jms.Connection;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import com.ibm.websphere.sib.api.jms.JmsConnectionFactory;
import com.ibm.websphere.sib.api.jms.JmsFactoryFactory;
import com.ibm.websphere.sib.api.jms.JmsQueue;
import com.ibm.websphere.sib.api.jms.JmsTopic;
/**
* Sample code to programmatically create a connection to a bus and
* send a text message.
*
* Example command lines:
* SIBusSender topic://my/topic?topicSpace=Default.Topic.Space MyBus localhost:7276
* SIBusSender queue://myQueue MyBus localhost:7286:BootstrapSecureMessaging InboundSecureMessaging
*/
public class SIBusSender {
/**
* #param args DEST_URL,BUS_NAME,PROVIDER_ENDPOINTS,[TRANSPORT_CHAIN]
*/
public static void main(String[] args) throws JMSException, IOException {
// Parse the arguments
if (args.length < 3) {
throw new IllegalArgumentException(
"Usage: SIBusSender <DEST_URL> <BUS_NAME> <PROVIDER_ENDPOINTS> [TARGET_TRANSPORT_CHAIN]");
}
String destUrl = args[0];
String busName = args[1];
String providerEndpoints = args[2];
String targetTransportChain = "InboundBasicMessaging";
if (args.length >= 4) targetTransportChain = args[3];
// Obtain the factory factory
JmsFactoryFactory jmsFact = JmsFactoryFactory.getInstance();
// Create a JMS destination
Destination dest;
if (destUrl.startsWith("topic://")) {
JmsTopic topic = jmsFact.createTopic(destUrl);
// Setter methods could be called here to configure the topic
dest = topic ;
}
else {
JmsQueue queue = jmsFact.createQueue(destUrl);
// Setter methods could be called here to configure the queue
dest = queue;
}
// Create a unified JMS connection factory
JmsConnectionFactory connFact = jmsFact.createConnectionFactory();
// Configure the connection factory
connFact.setBusName(busName);
connFact.setProviderEndpoints(providerEndpoints);
connFact.setTargetTransportChain(targetTransportChain);
// Create the connection
Connection conn = connFact.createConnection();
Session session = null;
MessageProducer producer = null;
try {
// Create a session
session = conn.createSession(false, // Not transactional
Session.AUTO_ACKNOWLEDGE);
// Create a message producer
producer = session.createProducer(dest);
// Loop reading lines of text from the console to send
System.out.println("Ready to send to " + dest + " on bus " + busName);
BufferedReader lineInput = new BufferedReader(new InputStreamReader(System.in));
String line = lineInput.readLine();
while (line != null && line.length() > 0) {
// Create a text message containing the line
TextMessage message = session.createTextMessage();
message.setText(line);
// Send the message
producer.send(message,
Message.DEFAULT_DELIVERY_MODE,
Message.DEFAULT_PRIORITY,
Message.DEFAULT_TIME_TO_LIVE);
// Read the next line
line = lineInput.readLine();
}
}
// Finally block to ensure we close our JMS objects
finally {
// Close the message producer
try {
if (producer != null) producer.close();
}
catch (JMSException e) {
System.err.println("Failed to close message producer: " + e);
}
// Close the session
try {
if (session != null) session.close();
}
catch (JMSException e) {
System.err.println("Failed to close session: " + e);
}
// Close the connection
try {
conn.close();
}
catch (JMSException e) {
System.err.println("Failed to close connection: " + e);
}
}
}
}
I created the queue in the IBM MQ Explorer.
My main doubt is how to do the connection and go on without application server.
I have been looking for some documentation/example for checking if a dynamically created topic exist and if it does, how to get the subscriber count for the topic.
I use following code for sending out message to a topic -
jmsTemplate.send(destination, new MessageCreator() {
#Override
public Message createMessage(Session session) throws JMSException {
TextMessage message = session.createTextMessage();
message.setText(commandStr);
return message;
}
});
This code seems to create the topic and publish message to topic.
I need to check if the topic exists before creating it.
Check if the topic have any subscriber.
Thanks in advance
i was able to find the solution to (1) problem (Hope this helps)-
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
ActiveMQConnection connection = (ActiveMQConnection)connectionFactory.createConnection();
connection.start();
DestinationSource ds = connection.getDestinationSource();
Set<ActiveMQTopic> topics = ds.getTopics();
To get the destination names, as you did it is correct, you can do it by JMX too specifically to get statistical information like subscriber count ...
import java.util.HashMap;
import java.util.Map;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import org.apache.activemq.broker.jmx.BrokerViewMBean;
import org.apache.activemq.broker.jmx.TopicViewMBean;
public class JMXGetDestinationInfos {
public static void main(String[] args) throws Exception {
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi");
Map<String, String[]> env = new HashMap<>();
String[] creds = { "admin", "admin" };
env.put(JMXConnector.CREDENTIALS, creds);
JMXConnector jmxc = JMXConnectorFactory.connect(url, env);
MBeanServerConnection conn = jmxc.getMBeanServerConnection();
ObjectName activeMq = new ObjectName("org.apache.activemq:type=Broker,brokerName=localhost");
BrokerViewMBean mbean = MBeanServerInvocationHandler.newProxyInstance(conn, activeMq, BrokerViewMBean.class,
true);
for (ObjectName name : mbean.getTopics()) {
if (("YOUR_TOPIC_NAME".equals(name.getKeyProperty("destinationName")))) {
TopicViewMBean topicMbean = MBeanServerInvocationHandler.newProxyInstance(conn, name,
TopicViewMBean.class, true);
System.out.println(topicMbean.getConsumerCount());
}
}
}
}
or
import java.util.Set;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
import org.apache.activemq.advisory.DestinationSource;
import org.apache.activemq.command.ActiveMQQueue;
import org.apache.activemq.command.ActiveMQTopic;
public class AdvisorySupportGetAllDestinationsNames {
public static void main(String[] args) throws JMSException {
Connection conn = null;
try {
ConnectionFactory cf = new ActiveMQConnectionFactory("tcp://localhost:61616");
conn = cf.createConnection();
conn.start();
DestinationSource destinationSource = ((ActiveMQConnection) conn).getDestinationSource();
Set<ActiveMQQueue> queues = destinationSource.getQueues();
Set<ActiveMQTopic> topics = destinationSource.getTopics();
System.out.println(queues);
System.out.println(topics);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
}
}
}
}
}
UPDATE
You can use AdvisorySupport.getConsumerAdvisoryTopic()
Note that the consumer start/stop advisory messages also have a
consumerCount header to indicate the number of active consumers on the
destination when the advisory message was sent.
So I have a simple JMS app, using a topic, powered by activeMQ. It works, but only 1 message is being sent (even though I am writing more lines in the console and so trying to send more stuff).
When I check the web console of ActiveMq, only 1 message is being sent (I also get this message in the ReceiverTopic class)...Why is this happening?
Below you can see my sender code:
package topic;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class SenderTopic {
private ConnectionFactory factory = null;
private Connection connection = null;
private Session session = null;
private Destination destination = null;
private MessageProducer producer = null;
private boolean jmsInitialized = false;
public SenderTopic() {
}
private void initJMS() throws JMSException {
factory = new ActiveMQConnectionFactory(ActiveMQConnection.DEFAULT_BROKER_URL);
connection = factory.createConnection();
connection.start();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
destination = session.createTopic("SAMPLE_TOPIC");
producer = session.createProducer(destination);
jmsInitialized = true;
}
private void sendMessage(String message) {
if (!jmsInitialized) {
try {
initJMS();
sendTextMessage(message);
} catch (JMSException e) {
jmsInitialized = false;
e.printStackTrace();
}
}
}
private void sendTextMessage(String message) throws JMSException {
TextMessage textMessage = session.createTextMessage(message);
producer.send(textMessage);
}
public static void main(String[] args) throws IOException {
SenderTopic receiver = new SenderTopic();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String message = reader.readLine();
receiver.sendMessage(message);
}
}
}
Intially the value of jmsInitialized is false, so your if condition (!jmsInitialized) will be true.
On second call of sendMessage the value of jmsInitialized will be true and the if condition fails because you are using not on boolean value.
You can add a else condition with only call to sendTextMessage.
try out this
private void sendMessage(String message) {
try {
if (!jmsInitialized) {
initJMS();
sendTextMessage(message);
}else{
sendTextMessage(message);
}
} catch (JMSException e) {
jmsInitialized = false;
e.printStackTrace();
}
}
}
I've a Queue in Wildfly 8.2.0 and deployed ear with listener. Then i'm trying to post Text Message to Remote Queue from Client program. In this scenario, unable to lookup Remote Connection Factory. Herewith attaching the program and error.
MDB Listener on Wildfly
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/queue/mdbtest")})
public class ExampleQueueMDB implements MessageListener {
#Override
public void onMessage(Message message) {
if (message instanceof TextMessage) {
try {
System.out.println("----------------");
System.out.println("Received: "
+ ((TextMessage) message).getText());
System.out.println("----------------");
} catch (JMSException e) {
e.printStackTrace();
}
} else {
System.out.println("----------------");
System.out.println("Received: " + message);
System.out.println("----------------");
}
}
}
Java Client Program
import java.util.logging.Logger;
import java.util.Properties;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.naming.Context;
import javax.naming.InitialContext;
public class HelloWorldJMSClientSample {
private static final Logger log = Logger.getLogger(HelloWorldJMSClient.class.getName());
// Set up all the default values
private static final String DEFAULT_MESSAGE = "Hello, World!";
private static final String DEFAULT_CONNECTION_FACTORY = "jms/RemoteConnectionFactory";
private static final String DEFAULT_DESTINATION = "jms/queue/mdbtest";
private static final String DEFAULT_MESSAGE_COUNT = "1";
private static final String DEFAULT_USERNAME = "user";
private static final String DEFAULT_PASSWORD = "pass";
private static final String INITIAL_CONTEXT_FACTORY = "org.jboss.naming.remote.client.InitialContextFactory";
//private static final String PROVIDER_URL = "http-remoting://localhost:8080";
private static final String PROVIDER_URL = "http-remoting://localhost:8080";
public static void main(String[] args) throws Exception {
ConnectionFactory connectionFactory = null;
Connection connection = null;
Session session = null;
MessageProducer producer = null;
MessageConsumer consumer = null;
Destination destination = null;
TextMessage message = null;
Context context = null;
try {
// Set up the context for the JNDI lookup
final Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
env.put(Context.PROVIDER_URL, PROVIDER_URL);
env.put(Context.SECURITY_PRINCIPAL, DEFAULT_USERNAME);
env.put(Context.SECURITY_CREDENTIALS, DEFAULT_PASSWORD);
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
context = new InitialContext(env);
// Perform the JNDI lookups
String connectionFactoryString = System.getProperty("connection.factory", DEFAULT_CONNECTION_FACTORY);
log.info("Attempting to acquire connection factory \"" + connectionFactoryString + "\"");
connectionFactory = (ConnectionFactory) context.lookup(connectionFactoryString);
log.info("Found connection factory \"" + connectionFactoryString + "\" in JNDI");
String destinationString = System.getProperty("destination", DEFAULT_DESTINATION);
log.info("Attempting to acquire destination \"" + destinationString + "\"");
destination = (Destination) context.lookup(destinationString);
log.info("Found destination \"" + destinationString + "\" in JNDI");
// Create the JMS connection, session, producer, and consumer
connection = connectionFactory.createConnection(DEFAULT_USERNAME,DEFAULT_PASSWORD);
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
producer = session.createProducer(destination);
// consumer = session.createConsumer(destination);
connection.start();
int count = Integer.parseInt(System.getProperty("message.count", DEFAULT_MESSAGE_COUNT));
String content = System.getProperty("message.content", DEFAULT_MESSAGE);
log.info("Sending " + count + " messages with content: " + content);
// Send the specified number of messages
for (int i = 0; i < count; i++) {
message = session.createTextMessage(content);
producer.send(message);
}
} catch (Exception e) {
log.severe(e.getMessage());
throw e;
} finally {
if (context != null) {
context.close();
}
// closing the connection takes care of the session, producer, and consumer
if (connection != null) {
connection.close();
}
}
}
}
ERROR
SEVERE: Failed to create session factory
Exception in thread "main" javax.jms.JMSException: Failed to create session factory
at org.hornetq.jms.client.HornetQConnectionFactory.createConnectionInternal(HornetQConnectionFactory.java:615)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnection(HornetQConnectionFactory.java:121)
at HelloWorldJMSClientSample.main(HelloWorldJMSClientSample.java:62)
Caused by: java.lang.IllegalStateException: The following keys are invalid for configuring a connector: http-upgrade-endpoint, http-upgrade-enabled
at org.hornetq.core.client.impl.ClientSessionFactoryImpl.checkTransportKeys(ClientSessionFactoryImpl.java:1227)
at org.hornetq.core.client.impl.ClientSessionFactoryImpl.<init>(ClientSessionFactoryImpl.java:181)
at org.hornetq.core.client.impl.ServerLocatorImpl.createSessionFactory(ServerLocatorImpl.java:589)
at org.hornetq.jms.client.HornetQConnectionFactory.createConnectionInternal(HornetQConnectionFactory.java:611)
... 2 more
Above error came while creating connection on line 62,
connection = connectionFactory.createConnection(DEFAULT_USERNAME,DEFAULT_PASSWORD);
I'm not sure, why this was not working. Hope this is a straight forward case. Please let me know, if there is different way to lookup RemoteConnectionFactory. Thanks.
Update:
Method 2:
If i use below configuration, able to call any ejb methods but still throwing error for RemoteConnectionFactory lookup.
// Set up the context for the JNDI lookup
final Properties env = new Properties();
env.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
env.put("endpoint.name", "client-endpoint");
env.put("remote.connections","default");
env.put("remote.connection.default.port","8080");
env.put("remote.connection.default.host","localhost");
env.put("remote.connection.default.username", DEFAULT_USERNAME);
env.put("remote.connection.default.password", DEFAULT_PASSWORD);
env.put("org.jboss.ejb.client.scoped.context",true);
context = new InitialContext(env);
Error after above change,
INFO: Attempting to acquire connection factory "jms/RemoteConnectionFactory"
SEVERE: Receive timed out
Exception in thread "main" javax.naming.CommunicationException: Receive timed out [Root exception is java.net.SocketTimeoutException: Receive timed out]
at org.jnp.interfaces.NamingContext.discoverServer(NamingContext.java:1317)
at org.jnp.interfaces.NamingContext.checkRef(NamingContext.java:1446)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:594)
at org.jnp.interfaces.NamingContext.lookup(NamingContext.java:587)
at javax.naming.InitialContext.lookup(InitialContext.java:411)
at HelloWorldJMSClientSample.main(HelloWorldJMSClientSample.java:56)
Caused by: java.net.SocketTimeoutException: Receive timed out
at java.net.PlainDatagramSocketImpl.receive0(Native Method)
at java.net.AbstractPlainDatagramSocketImpl.receive(AbstractPlainDatagramSocketImpl.java:146)
at java.net.DatagramSocket.receive(DatagramSocket.java:816)
at org.jnp.interfaces.NamingContext.discoverServer(NamingContext.java:1287)
... 5 more
Error came on lookup, line 56,
connectionFactory = (ConnectionFactory) context.lookup(connectionFactoryString);
Please provide any solution for this problem. Thanks.
Found answer from https://developer.jboss.org/thread/265919.
Since i'm working with infinispan, i've used the infinispan version(6.0.2) of Wildfly 8.2.0 for client program. But Wildfly using HornetQ 2.4.5 and client having HornetQ 2.2.7. I've changed to HornetQ 2.4.5 on client side and everything working fine.
THE SCENE:
I am writing a echo client and server. The data being transfered is a string:
Client encode a string,and send it to server.
Server recv data, decode string, then encode the received string, send it back to client.
The above process will be repeated 100000 times.(Note: the connection is persistent).
DEFERENT CONTIONS:
When I run ONE server and TWO client at the same time, everything is ok,every client receives 100000 messages and terminated normally.
But When I add a ExecutionHandler on server, and then run ONE server and TWO client at the same time, one client will never terminate, and the network traffic is zero.
I cant locate the key point of this problem for now, will you give me some suggestions?
MY CODE:
string encoder , string decoder, client handler , server handler , client main ,server main.
//Decoder=======================================================
import java.nio.charset.Charset;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
public class Dcd extends FrameDecoder {
public static final Charset cs = Charset.forName("utf8");
#Override
protected Object decode(ChannelHandlerContext ctx, Channel channel,
ChannelBuffer buffer) throws Exception {
if (buffer.readableBytes() < 4) {
return null;
}
int headlen = 4;
int length = buffer.getInt(0);
if (buffer.readableBytes() < length + headlen) {
return null;
}
String ret = buffer.toString(headlen, length, cs);
buffer.skipBytes(length + headlen);
return ret;
}
}
//Encoder =======================================================
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.oneone.OneToOneEncoder;
public class Ecd extends OneToOneEncoder {
#Override
protected Object encode(ChannelHandlerContext ctx, Channel channel,
Object msg) throws Exception {
if (!(msg instanceof String)) {
return msg;
}
byte[] data = ((String) msg).getBytes();
ChannelBuffer buf = ChannelBuffers.dynamicBuffer(data.length + 4, ctx
.getChannel().getConfig().getBufferFactory());
buf.writeInt(data.length);
buf.writeBytes(data);
return buf;
}
}
//Client handler =======================================================
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
/**
* Handler implementation for the echo client. It initiates the ping-pong
* traffic between the echo client and server by sending the first message to
* the server.
*/
public class EchoClientHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger
.getLogger(EchoClientHandler.class.getName());
private final AtomicLong transferredBytes = new AtomicLong();
private final AtomicInteger counter = new AtomicInteger(0);
private final AtomicLong startTime = new AtomicLong(0);
private String dd;
/**
* Creates a client-side handler.
*/
public EchoClientHandler(String data) {
dd = data;
}
public long getTransferredBytes() {
return transferredBytes.get();
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) {
// Send the first message. Server will not send anything here
// because the firstMessage's capacity is 0.
startTime.set(System.currentTimeMillis());
Channels.write(ctx.getChannel(), dd);
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
// Send back the received message to the remote peer.
transferredBytes.addAndGet(((String) e.getMessage()).length());
int i = counter.incrementAndGet();
int N = 100000;
if (i < N) {
e.getChannel().write(e.getMessage());
} else {
ctx.getChannel().close();
System.out.println(N * 1.0
/ (System.currentTimeMillis() - startTime.get()) * 1000);
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
// Close the connection when an exception is raised.
logger.log(Level.WARNING, "Unexpected exception from downstream.",
e.getCause());
e.getChannel().close();
}
}
//Client main =======================================================
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
/**
* Sends one message when a connection is open and echoes back any received data
* to the server. Simply put, the echo client initiates the ping-pong traffic
* between the echo client and server by sending the first message to the
* server.
*/
public class EchoClient {
private final String host;
private final int port;
public EchoClient(String host, int port) {
this.host = host;
this.port = port;
}
public void run() {
// Configure the client.
final ClientBootstrap bootstrap = new ClientBootstrap(
new NioClientSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
// Set up the pipeline factory.
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new Dcd(), new Ecd(),
new EchoClientHandler("abcdd"));
}
});
bootstrap.setOption("sendBufferSize", 1048576);
bootstrap.setOption("receiveBufferSize", 1048576);
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("writeBufferLowWaterMark", 32 * 1024);
bootstrap.setOption("writeBufferHighWaterMark", 64 * 1024);
List<ChannelFuture> list = new ArrayList<ChannelFuture>();
for (int i = 0; i < 1; i++) {
// Start the connection attempt.
ChannelFuture future = bootstrap.connect(new InetSocketAddress(
host, port));
// Wait until the connection is closed or the connection
// attempt
// fails.
list.add(future);
}
for (ChannelFuture f : list) {
f.getChannel().getCloseFuture().awaitUninterruptibly();
}
// Shut down thread pools to exit.
bootstrap.releaseExternalResources();
}
private static void testOne() {
final String host = "192.168.0.102";
final int port = 8000;
new EchoClient(host, port).run();
}
public static void main(String[] args) throws Exception {
testOne();
}
}
//server handler =======================================================
import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
/**
* Handler implementation for the echo server.
*/
public class EchoServerHandler extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger
.getLogger(EchoServerHandler.class.getName());
private final AtomicLong transferredBytes = new AtomicLong();
public long getTransferredBytes() {
return transferredBytes.get();
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) {
// Send back the received message to the remote peer.
transferredBytes.addAndGet(((String) e.getMessage()).length());
Channels.write(ctx.getChannel(), e.getMessage());
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) {
// Close the connection when an exception is raised.
logger.log(Level.WARNING, "Unexpected exception from downstream.",
e.getCause());
e.getChannel().close();
}
}
//Server main =======================================================
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.execution.ExecutionHandler;
import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
/**
* Echoes back any received data from a client.
*/
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public void run() {
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
System.out.println(Runtime.getRuntime().availableProcessors() * 2);
final ExecutionHandler executionHandler = new ExecutionHandler(
new OrderedMemoryAwareThreadPoolExecutor(16, 1048576, 1048576));
// Set up the pipeline factory.
bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
public ChannelPipeline getPipeline() throws Exception {
System.out.println("new pipe");
return Channels.pipeline(new Dcd(), new Ecd(),
executionHandler, new EchoServerHandler());
}
});
bootstrap.setOption("child.sendBufferSize", 1048576);
bootstrap.setOption("child.receiveBufferSize", 1048576);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.writeBufferLowWaterMark", 32 * 1024);
bootstrap.setOption("child.writeBufferHighWaterMark", 64 * 1024);
// Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(port));
}
public static void main(String[] args) throws Exception {
int port = 8000;
new EchoServer(port).run();
}
}
I have found the reason now, it is a hard work, but full with pleasure.
When added a ExecutionHandler, the message will be wrapped into a Runnable task, and will be executed in a ChildExecutor. The key point is here : A task maybe added to ChildExecutor when the executor almostly exit , then is will be ignored by the ChildExecutor.
I added three lines code and some comments, the final code looks like below, and it works now,should I mail to the author? :
private final class ChildExecutor implements Executor, Runnable {
private final Queue<Runnable> tasks = QueueFactory
.createQueue(Runnable.class);
private final AtomicBoolean isRunning = new AtomicBoolean();
public void execute(Runnable command) {
// TODO: What todo if the add return false ?
tasks.add(command);
if (!isRunning.get()) {
doUnorderedExecute(this);
} else {
}
}
public void run() {
// check if its already running by using CAS. If so just return
// here. So in the worst case the thread
// is executed and do nothing
boolean acquired = false;
if (isRunning.compareAndSet(false, true)) {
acquired = true;
try {
Thread thread = Thread.currentThread();
for (;;) {
final Runnable task = tasks.poll();
// if the task is null we should exit the loop
if (task == null) {
break;
}
boolean ran = false;
beforeExecute(thread, task);
try {
task.run();
ran = true;
onAfterExecute(task, null);
} catch (RuntimeException e) {
if (!ran) {
onAfterExecute(task, e);
}
throw e;
}
}
//TODO NOTE (I added): between here and "isRunning.set(false)",some new tasks maybe added.
} finally {
// set it back to not running
isRunning.set(false);
}
}
//TODO NOTE (I added): Do the remaining works.
if (acquired && !isRunning.get() && tasks.peek() != null) {
doUnorderedExecute(this);
}
}
}
This was a bug and will be fixed in 3.4.0.Alpha2.
See https://github.com/netty/netty/issues/234