I am using Java SE. I create a topic when the app first starts like so:
connectionFactory = new ActiveMQConnectionFactory("vm://localhost");
conn = connectionFactory.createTopicConnection();
session = conn.createTopicSession(false,
TopicSession.AUTO_ACKNOWLEDGE);
conn.start();
session.createTopic(name);
I am confused on how to retrieve this Topic in my classes.
Say for example I have a class, and it connects to the JMS Service just like above using:
connectionFactory = new ActiveMQConnectionFactory("vm://localhost");
conn = connectionFactory.createTopicConnection();
session = conn.createTopicSession(false,
TopicSession.AUTO_ACKNOWLEDGE);
conn.start();
How can I then get a reference to the Topic I created a app startup to send messages?
I would imagine something along the lines of:
session.getTopic(name);
Would exist, but I cant find anything on it.
I have read how to do this using Java EE using JNDI lookup, but this service is not available to me since I am not running in a container.
You don't 'retrieve' a topic. A Topic instance is just a piece of information. You construct an instance of it in your client if you want to subscribe to a topic (or queue), like is demonstrated in the ActiveMQ hello world example:
http://activemq.apache.org/hello-world.html
ex:
// the name should of course be the same as it exists on the producer side
Destination destination = session.createTopic("TEST.FOO");
// Create a MessageConsumer from the Session to the Topic or Queue
MessageConsumer consumer = session.createConsumer(destination);
This is all governed by the standardized and very mature JMS API, so you should refer to the JEE documentation. Any book on JMS will work for you as well.
Further reading: https://docs.oracle.com/javaee/6/tutorial/doc/bncdr.html
API docs: http://docs.oracle.com/javaee/6/api/javax/jms/package-summary.html
Related
I have already working application based on Azure EventHub. Now I need write java receiver that connects to the existing infrastructure.
Existing configuration:
Event Hub > SomeName > Consumer Group > SomeGroupName
In the administrative console I cannot see any QUEUE or TOPIC definitions. Analyzing working c# code I can see that hub-name + group-name is enough to connect.
I have reconstructed url that allows me to connect over java (and connection works so far).
amqps://SomeName.servicebus.windows.net
So my questions:
1) When instead of queue /topic I specify group-name then I get exception The messaging entity 'sb://SomeName.servicebus.windows.net/SomeGroupName' could not be found. What is the model used there instead of queue/topic?
2) How to work with such infrastructure from Apache-qpid?
Are you using the Event Hub created in the old portal or one created using the new portal?
EventHub is not a Message Bus, so there are no Queues or Topics, that is correct.
The consumer group is not a part of the address. The address is build using the namespace and the name of the eventhub in that namespace.
So the address becomes:
sb://SomeNameSpaceName.servicebus.windows.net/SomeEventHubName
Can you post the c# code you've analyzed? Since you have an already working application maybe we can workout the differences that prevents it from working now.
The greatest hint for resolve the question gave me following link: http://theitjourney.blogspot.com/2015/12/sendreceive-messages-using-amqp-in-java.html
So No queue neither topic in this model. You need to connect to specific provider and specify correct EventHub as following:
application.properties:
connectionfactory.SBCF=amqps://<PolicyName>:<PolicyKey>#<DomainName>.servicebus.windows.net
queue.EventHub=<EventHubName>/ConsumerGroups/$Default/Partitions/0
Where:
After that following code allowed me to create MessageConsumer:
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY,
"org.apache.qpid.amqp_1_0.jms.jndi.PropertiesFileInitialContextFactory");
env.put(Context.PROVIDER_URL,
getClass().getResource("/application.properties").toString());
Context context = null;
context = new InitialContext(env);
// Look up ConnectionFactory
ConnectionFactory cf = (ConnectionFactory) context.lookup("SBCF");
Destination queue = (Destination) context.lookup("EventHub");
// Create Connection
Connection connection = cf.createConnection();
// Create receiver-side Session, MessageConsumer
Session receiveSession = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageConsumer receiver = receiveSession.createConsumer(queue);
How can I check whether a queue exists on a JMS server using the Java API? I don't want to send or receive any data to the queue for now, just verify that the queue exists. Also, the queue may be empty.
Here is my code sample. I have removed the error handling for simplicity.
Connection connection = null;
Session session = null;
connection = factory.createConnection();
session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
//I was hoping this next line would throw an exception if the queue does not exist
Queue queue = session.createQueue(queueName);
My JMS server is TIBCO EMS. I'm hoping for a solution that works on versions 5-7.
Solution
I followed the recommendation in the accepted answer but created a browser instead. The following line threw an exception as desired:
QueueBrowser browser = session.createBrowser(queue);
This is dependent on the provider, but you wont know in most cases until you create the session type, such as session.createConsumer. Simply creating a consumer this way will not consume any messages until you do a receive. And it is here the behavior may change from provider to provider and configuration of the server.
For example with ActiveMQ, assuming there are no permissions blocking the user you are connecting with, the queue is created automatically when you create the session type.
With WebSphere MQ, the queue has to be defined by an admin. If it does not exist, the queue manager will return an exception with a reason code of 2085 (UNKNOWN_OBJECT_NAME).
Outside of this, you'd need to see if the particular provider had a way to access a list of queues. Using the above examples, ActiveMQ you can get the list of queues using JMX, with WebSphere MQ, you can do this if you have permissions to send PCF commands to the queue manager.
Try creating a consumer or producer off the Session passing in the queue object you just created:
session.createConsumer(queue);
This should throw an InvalidDestinationException if the queue (or topic) does not exist.
I am trying to develop a JMS standalone application to read and write to a Queue on MQSeries.
My boss asked me to use pure java JMS (not ibm.mq lib) to do that.
Here is the information that need to make the jms connection:
mq.hostname=10.10.10.10
mq.channel=API.CLIENTCHL
mq.queueManager=MQPETAPI
mq.port=1422
Do you know how to do that Or do you have any link that teach me to do that.
The issue here is the requirement that "My boss asked me to use pure java JMS (not ibm.mq lib) to do that." JMS is a specification and each implementation must comply with the API and the semantics, but is free to do whatever they want at a low level. It is always necessary to use the implementation classes provided by the transport vendor. Therefore if you use WebSphere MQ as the transport, you will need to use the IBM MQ JMS classes to write a JMS application.
That said, if you stick with pure JMS API calls you would be able to plug in any transport vendor's classes. This is what is usually intended when you are given requirements such as that mentioned in the original post.
There's an article describing exactly what you are looking to do called Running a standalone Java application on WebSphere MQ V6.0 It uses only the JMS API and it uses JNDI in a local file system (a .bindings file). By swapping out the IBM JMS classes for another vendor and using their JNDI tools you would be able to plug in any JMS transport without changing your code using this approach.
If you want to do the same thing without JNDI, look at the sample programs provided with the MQ client install where you obtained your Java classes. In a UNIX/Linux system these are in /opt/mqm/samp and on Windows they are in install_dir/tools/jms/samples. The SimpleRequestor.java sample has the following code for initializing your connection factory without JNDI:
try {
// Create a connection factory
JmsFactoryFactory ff = JmsFactoryFactory.getInstance(WMQConstants.WMQ_PROVIDER);
JmsConnectionFactory cf = ff.createConnectionFactory();
// Set the properties
cf.setStringProperty(WMQConstants.WMQ_HOST_NAME, "localhost");
cf.setIntProperty(WMQConstants.WMQ_PORT, 1414);
cf.setStringProperty(WMQConstants.WMQ_CHANNEL, "SYSTEM.DEF.SVRCONN");
cf.setIntProperty(WMQConstants.WMQ_CONNECTION_MODE, WMQConstants.WMQ_CM_CLIENT);
cf.setStringProperty(WMQConstants.WMQ_QUEUE_MANAGER, "QM1");
Because this approach does not use JNDI, you are required to write code that is not transportable across transport vendors. It is IBM WebSphere MQ specific.
If you grabbed the MQ jars from somewhere and do not have the full install (and thus do not have the samples) you can download it as SupportPac MQC7. The download is free. In general you should use the latest client, even with a back-level queue manager. Obviously you do not get V7 functionality from a V6 QMgr but the JMS implementation in the V7 client is much improved, even for V6 functionality. If for some reason you really must use the V6 client, you can download it as SupportPacMQC6. Whichever client version you use, make sure to use the corresponding Infocenter.
V6 Infocenter
V7 Infocenter
Finally, the landing page with an index for all the SupportPacs is here.
A complete (synchronous) standalone JMS application with TextMessage.
It is IBM WebSphere MQ specific.
import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueReceiver;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.jms.Session;
import javax.jms.TextMessage;
import com.ibm.mq.jms.JMSC;
import com.ibm.mq.jms.MQQueueConnectionFactory;
public class JMSApplicationStandAlone {
public static void main(String[] args) {
try {
/*MQ Configuration*/
MQQueueConnectionFactory mqQueueConnectionFactory = new MQQueueConnectionFactory();
mqQueueConnectionFactory.setHostName("localhost");
mqQueueConnectionFactory.setChannel("MQ.CHANNEL");//communications link
mqQueueConnectionFactory.setPort(1416);
mqQueueConnectionFactory.setQueueManager("QUEUE.MGR");//service provider
mqQueueConnectionFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
/*Create Connection */
QueueConnection queueConnection = mqQueueConnectionFactory.createQueueConnection();
queueConnection.start();
/*Create session */
QueueSession queueSession = queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
/*Create response queue */
Queue queue = queueSession.createQueue("QUEUE.RESPONSE");
/*Create text message */
TextMessage textMessage = queueSession.createTextMessage("put some message here");
textMessage.setJMSReplyTo(queue);
textMessage.setJMSType("mcd://xmlns");//message type
textMessage.setJMSExpiration(2*1000);//message expiration
textMessage.setJMSDeliveryMode(DeliveryMode.PERSISTENT); //message delivery mode either persistent or non-persistemnt
/*Create sender queue */
QueueSender queueSender = queueSession.createSender(queueSession.createQueue("QUEUE.REQEST"));
queueSender.setTimeToLive(2*1000);
queueSender.send(textMessage);
/*After sending a message we get message id */
System.out.println("after sending a message we get message id "+ textMessage.getJMSMessageID());
String jmsCorrelationID = " JMSCorrelationID = '" + textMessage.getJMSMessageID() + "'";
/*Within the session we have to create queue reciver */
QueueReceiver queueReceiver = queueSession.createReceiver(queue,jmsCorrelationID);
/*Receive the message from*/
Message message = queueReceiver.receive(60*1000);
String responseMsg = ((TextMessage) message).getText();
queueSender.close();
queueReceiver.close();
queueSession.close();
queueConnection.close();
} catch (JMSException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Note: Replace the configuration values
If you don't mind writing WMQ-specific code then you can do
MQConnectionFactory cf = new MQConnectionFactory();
cf.setHostName(HOSTNAME);
cf.setPort(PORT);
cf.setChannel(CHANNEL);
cf.setQueueManager(QMNAME);
cf.setTransportType(WMQConstants.WMQ_CM_CLIENT);
then usual JMS resources
Connection c = cf.createConnection();
Session s = c.createSession(false, Session.AUTO_ACKNOWLEDGE);
Queue q = s.createQueue("myQueue"); // replace with real queue name
MessageProducer p = s.createProducer(q);
and finally create and send a message
Message m = s.createTextMessage("Hello, World!);
p.send(m);
(i've typed that in off the top of my head so can't rule out a typo, but it's fundamentally correct). If you're really supposed to be using 'pure JMS' - i.e. with no provider-specific objects - then you need to bind a MQConnectionFactory object in JNDI (take a look at the JMSAdmin tool, it's in the docs) then look it up from your application, i.e.
InitialContext ic = new InitialContext(); // or as appropraite
ConnectionFactory cf = (ConnectionFactory)ic.lookup("myMQfactory"); // replace with JNDI name
Typically with JMS you would define the QueueConnectionFactory in your container via whatever configuration mechanism it makes available then add it to the container's JNDI registry. Each container would have it's own methods for doing that (i.e. Tomcat versus WebSphere).
If you want to forgo JNDI, you could create an instance of com.ibm.mq.jms.MQQueueConnectionFactory directly and set the hostname, port, queueManager, and channel properties on it. You can then use that object as you would an instance of javax.jms.QueueConnectionFactory since it implements it.
I can't teach you JMS in a single post, but I can point you to some of the resources that I used to learn it myself:
The O'Reilly Java Message Service book
IBM Developerworks JMS Tutorial (more MQSeries/Websphere MQ specific)
The Spring framework can help you use JMS more effectively, especially if you're developing a standalone app outside of a J2EE app server: Spring Java Message Service documentation
This is fairly common. Here are some examples.
I've set up ActiveMQ and I can create/connect to a topic using "dynamicTopics/MyTopic". This works great:
Properties env = new Properties( );
env.setProperty(Context.INITIAL_CONTEXT_FACTORY,"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
env.setProperty(Context.PROVIDER_URL,"tcp://myhostname:xxxxx");
javax.naming.Context ctx = new InitialContext(env);
InitialContext jndi = new InitialContext(env);
// Look up a JMS connection factory
TopicConnectionFactory conFactory = (TopicConnectionFactory)jndi.lookup("TopicConnectionFactory");
// Create a JMS connection
TopicConnection connection = conFactory.createTopicConnection(username,password);
Topic chatTopic = (Topic)jndi.lookup("dynamicTopics/MyTopic");
I would like to connect to a topic already exists without dynamically creating the topic if it doesn't exist, how can I do so?
Cheers,
Pete
While you don't need to create destinations manually with AMQ you always have that option. Basically you can alter the security settings to allow only an admin to create destinations. See the AMQ FAQ for this:
http://activemq.apache.org/how-do-i-create-new-destinations.html
Regards
Tim
www.fusesource.com
What you are actually doing is just connecting to topic. ActiveMQ is so nice that it creates topic for you if it did not exist before.
So, to connect to already existing topic just do the same that you are already doing.
I am using Glassfish JMS.
I am able to add messages to a queue.
I can see the messages using the QueueBrowser object.
However the MessageConsumer (nor the QueueReceiver) cannot receice any message and return null.
Message expiration is set to 0 and I remember to open the connection.
Any ideas?
Here is the code:
Session session = null;
Connection conn = null;
try
{
InitialContext jndi = new InitialContext();
ConnectionFactory qFactory = (ConnectionFactory)jndi.
lookup("myConnectionFactory");
conn = qFactory.createConnection();
conn.start();
Queue queue = (Queue)jndi.lookup("myQueueName");
session = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
QueueReceiver mc = ((QueueSession)session).createReceiver(queue);
Object m = mc.receive(2000);
//m is NULL!
QueueBrowser browser = session.createBrowser(queue);
for(Enumeration e = browser.getEnumeration(); e.hasMoreElements(); )
{
//there are many messages here...
}
That would be good to have the client code.
Similar thing happened to me when not properly committing/closing the connection on the sender side. The message would be visible when using the admin console, however, not available yet to the MDB.
Hope it helps.
Does this code run in the appserver? If it does, I'd obtain the required objects via annotations, and for a message receiver I'd use a MDB.
If this is a piece of standalone code, I had a hell of a time getting a JNDI based client working, I reverted to using the "raw" Java API.
I witnessed the same behavior happening after the first session commit, meaning that before the messages where received correctly. In my case the issue was that I was re-creating the receiver while keeping the same session.
As pointed out in this article:
Creating temporary destinations, consumers, producers and connections
are all synchronous request-response operations with the broker and so
should be avoided for processing each request as it results in lots of
chat with the JMS broker.
The solution was as simple as reusing the same receiver.