Maybe it is a extreme newbie question, but:
I'm about to implement sending a message to a queue. The problem is, all I know is that it is a JMS Queue, but no idea, which implementation (it is just called ESB).
So now I have to have a connectionFactory bean, and all examples I saw use ActiveMqConnectionFactory. Is there any generic factory/implementation? JMS is a standard, so I should not be bound to some specific factory implementation, right?
Correct. What you need is javax.jms.ConnectionFactory and javax.jms.Destination.
However, as you say it is ESB, there should some connection properties to the server, e.g. JNDI, or some service-locator to connect to the bus and call appropriate service.
Actually not enough info, what you have in hands regarding that ESB
Related
I am using Spring Boot with spring-rabbitmq. My connection factory is configured in application.properties and it seems to be nice.
My aim is: during start check if exists queue if specific name, and in case of absence create such queue. I am not sure how to deal with it. What beans should I create in config class? From what I read it should be RabbitAdmin, however I am not sure about it. Can you help me?
Everything is described clearly in the Reference Manual:
The AMQP specification describes how the protocol can be used to configure Queues, Exchanges and Bindings on the broker. These operations which are portable from the 0.8 specification and higher are present in the AmqpAdmin interface in the org.springframework.amqp.core package.
And further:
When the CachingConnectionFactory cache mode is CHANNEL (the default), the RabbitAdmin implementation does automatic lazy declaration of Queues, Exchanges and Bindings declared in the same ApplicationContext.
So, you should declare Queue, Exchange and Binding beans in your application context and AmqpAdmin will take care about their definition on the target Broker.
There must be a note that according AMQP protocol, if entity already exists on the Broker, the declaration is just silent and idempotent.
So, in your case you don't need to worry about queues existence and just provide their declarations as beans in the application context.
I am currently successfully using an MQConnectionFactory to connect and post to a Websphere MQ queue using JMS.
However I'm getting a requirement from a client that I must use mqclient.ini instead.
So my question is, for a 'standard' JMS setup, should I be using:
Straight up MQConnectionFactory instance
A JMS configuration file
An mqclient.ini file
? What would one use one over the other? Does one take precedence over another?
The mqclient.ini and JMSconfig files are used setting attributes like what client side exits to use, TCP level overrides etc. They are basically used for configuring the client libraries/jars. They are not meant for application configuration for example what queue manager or queue to use. This sort of info, connection factory or destination info, is typically pulled from a JNDI so that the configuration can be modified without affecting application.
Tomcat has a built-in JDBC connection pooling, but unfortunately no built-in JMS connection pooling.
We are migrating a legacy Tomcat web application from WebSphere MQ version 6 to 7.
Unfortunately, connection pooling has been removed in WebSphere MQ 7 as described here: http://www-01.ibm.com/support/docview.wss?uid=swg21665128
Now we are afraid that we will run into troubles if we just use the following code for configuring MQ in Tomcat:
<Resource name="jms/XXXQCF" auth="Container"
type="com.ibm.mq.jms.MQQueueConnectionFactory" factory="com.ibm.mq.jms.MQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory"
HOST="xxx.com" PORT="1429" CHAN="XXX" TRAN="1"
QMGR="XXX" />
The reason for our concerns is that this will not use a pooled JMS provider when using MQ 7. For details, see also http://activemq.apache.org/jmstemplate-gotchas.html
Alternative solutions we see are:
1) Use of Atomikos
Atomikos has a com.atomikos.jms.AtomikosConnectionFactoryBean that can be used instead of MQQueueConnectionFactory
But using an XA transaction manager is a huge overhead when we don't need XA
2) Use Spring's CachingConnectionFactory
looks like a good solution, but unfortunately our legacy application does not use Spring.
So we assume that using CachingConnectionFactory would mean quite some effort.
3) Use Apache Commons Pool
looks promising too, but implementing it correctly for JMS will require some good JMS knowledge
Our questions:
is there a JMS provider that can be used to wrap MQQueueConnectionFactory and that will pool connections, sessions, producers and consumers?
did anyone succeed in implementing one of the alternative solutions we outlined above?
As proposed by Umapathy in option 3, we now opted for the approach using Spring's CachingConnectionFactory, and it works well even for a non-Spring application. All you need to do is add the Spring Jars to the classpath, and wrap the MQQueueConnectionFactory with a CachingConnectionFactory.
We chose to create our own Tomcat QueueConnectionFactoryFactory that enables us to leave the original application code completely untouched, you just need to replace the original MQ connection factory from the Tomcat configuration file (shown above in the question) with the following XML definition:
<Resource name="jms/XXXQCF" auth="Container"
type="org.springframework.jms.connection.CachingConnectionFactory"
factory="at.rsf4j.core.utilities.RSFCachingMQQueueConnectionFactoryFactory"
description="JMS Queue Connection Factory"
HOST="xxx.com" PORT="1429" CHAN="XXX" TRAN="1"
QMGR="XXX" />
Here is the (simplified) code (without error checking) for the RSFCachingMQQueueConnectionFactoryFactory:
public class RSFCachingMQQueueConnectionFactoryFactory implements ObjectFactory{
public Object getObjectInstance (Object obj, Name name, Context nameCtx, Hashtable<?,?> environment)
throws NamingException {
Reference ref = (Reference) obj;
String beanClassName = ref.getClassName();
Class<?> beanClass = Class.forName(beanClassName);
if (CachingConnectionFactory.class.isAssignableFrom(beanClass)){
MQQueueConnectionFactoryFactory cff = new MQQueueConnectionFactoryFactory();
Reference mqReference = new Reference(
MQQueueConnectionFactory.class.getName());
Enumeration<RefAddr> allAddrs = ref.getAll();
while (allAddrs.hasMoreElements()){
mqReference.add(allAddrs.nextElement());
}
MQQueueConnectionFactory cf = (MQQueueConnectionFactory)cff.getObjectInstance(mqReference, name, nameCtx, environment);
CachingConnectionFactory ccf = (CachingConnectionFactory)beanClass.newInstance();
ccf.setTargetConnectionFactory(cf);
return ccf;
}
}
I think you already know the answer.
option 1: Go with a Java EE application server. This has inbuilt JMS pools.
option 2: If this is a simple application that does a single job (like putting on a queue with fire and forget type), you can connect to the JMS provider (qmgr) and create the producer or consumer in the servlet_init method. This means the legacy code needs an update. You also need to take care of the reconnect when something breaks as JMS reconnect properties doesn't kick off a reconnection (as far as my experience goes).
option 3: I have gone with Spring's CachingConnectionFactory when the application happens to be more than a little complex than one in option 2. I have applications that use JMSTemplate and some doesn't.
I have a #Singleton EJB which is started at #Startup, this bean listens to multicast traffic using netty. And what I would like to do is, on receipt of a message over multicast, send a JMS message on an injected topic (so on Wildfly, with JMS 2.0, I have the following:)
#Resource(lookup = "java:/jboss/exported/jms/topic/appUpdates")
private Topic appUpdate;
#Inject
private JMSContext context;
I know there are no problems with the topic and publishing a message if I have a #Scheduled function in the ejb, I can happily create a publisher and send a message. However attempt to publish JMS message from the netty event loop context results in:
2:10:34,441 ERROR [stderr] (nioEventLoopGroup-0-1)
java.lang.RuntimeException: javax.naming.NameNotFoundException:
java:comp/TransactionSynchronizationRegistry 12:10:34,441 ERROR
[stderr] (nioEventLoopGroup-0-1) at
org.jboss.as.messaging.deployment.JMSContextProducer$JMSContextWrapper.getDelegate(JMSContextProducer.java:217)
So my question is, what is the correct way to publish from the let's say non-jboss context (Netty event loop) to the JMS topic?
EDIT: I see now that I'm actually breaking the EJB spec by trying to get my bean to listen to the multicast traffic, so, now the question is, short of writing a resource adapter, is there any simpler way to do this?
(Server: Wildfly 8.2.0.Final using standalone-full.xml config)
My previous answer is crap - the correct way to do this is to create a JCA Resource Adapter - which I ended up creating in the end. Now I don't need the JMS topic anymore as my MDBs listen directly to the events from the inbound connection.
The only complication is that there is little documentation on how to do this with the 1.7 spec (using annotations), so one has to look at the xml config used for 1.5 etc. and apply appropriate annotations.
I'm trying to get a pooled JDBC DataSource in my application. I'm writing an open-source library, and want to make configuration as, well, configurable as possible. I'd rather not use JNDI or force the use of any particular type of configuration file.
Right now, I do this:
MysqlConnectionPoolDataSource ds = new MysqlConnectionPoolDataSource();
ds.setDatabaseName("blah");
ds.setUrl("jdbc:mysql://blaggablah");
ds.setUser("jimbob");
ds.setPassword("dweezil");
Obviously not ideal if you want to use something other than MySQL in the future.
Is there some kind of generic PooledDataSourceFactory that will take a few parameters, like database type and connection info, and give me a pooled DataSource?
I'm not sure what kind of application (library?) you are creating, but unless it's a web app. stack or something, you could ask the client programmer to pass-in the datasource, e.g. via the constructor. This is really the gist of dependency injection.
If you app. is e.g. a web app. stack like Django, you can still make it so that you internally pass a datasource to your middleware (a.k.a DI). Such design facilitates modularity, and makes it easy to use that part of code in other projects. However, you'll have to go from configuration to DataSource somehow, so at some point you need to decide what the mechanism for that will be (e.g. JNDI). I think that's perfectly acceptable.
You can use a standard pooling/caching library and let the use configure it. Like Apache Jakarta Pool, or ehcache?