Proposal: resource declarations without JCA
(this partially solves #251, but still requires some way of configuration injection. If necessary, I can pare this down to the bare minimum that is needed for CF definition)
One of the things in JMS 2.1 (or rather Java EE 6) that are incredibly useful in theory, but terrible in practice are resource definitions. @JMSConnectionFactoryDefinition looks a lot like JDBC @DataSourceDefinition, but is much more cumbersome to use:
- it requires JCA adapters for each message broker, which must be deployed into the application server, are often poorly documented, and even functionally incomplete
-
@MessageDrivenbeans, the place where you would expect to get away with just JNDI names of the factory and the destination plus the destination name, do not work with such JMS resources without vendor-specific ActivationConfigProperties
Better @JMSConnectionFactoryDefinition and @JMSDestinationDefinition should possess the following traits:
- create JMS resources that are indistinguishable from those created by the application server
- not require any additional wrappers around existing libraries that implement JMS interfaces
- use the same configuration properties as existing JMS libraries
This will allow Jakarta EE developers to create applications that work equally well with existing application servers running Java EE 6 or 7 (by not declaring JMS resources in their code) as well as with cloud native lightweight application servers that support the next version of JMS and that can be packaged as uberjars or hollow jars + skinny jars, all this without vendor-specific code.
The changes to the annotations, interfaces and the expected behavior that, in my opinion, will achieve that are outlined below.
JMSConnectionFactoryDefinition
- when
resourceAdapter()is not set,className()is used to select a class from the classpath, not from the default resource adapter;interfaceName()is used to disambiguate in cases when the class implements several JMS connection factory interfaces -
XAConnectionFactoryand its subinterfaces are added to the list of allowed connection factory interfaces, the application server must provide their non-XA counterparts as JNDI resources and manage transactions transparently - it's a runtime error when
interfaceName()isXAConnectionFactoryor its subinterface andtransactional()is false -
user()andpassword()are used to callConnectionFactory.createConnection()andConnectionFactory.createContext() - when
resourceAdapter()is not set,properties()must set the properties of the instantiated connection factory class, which must be a JavaBean
JMSDestinationDefinition
- when
resourceAdapter()is not set,className()is used to select a class from the classpath, not from the default resource adapter;interfaceName()is used to disambiguate in cases when the class implements several JMS connection factory interfaces -
destinationName()must be used to create destinations in a JMS-standard way - String
connectionFactoryLookup()must be added to the interface. It can be used instead ofclassName()orresourceAdapter()to create a destination
ConnectionFactory
- Queue createQueue(String name) and Topic createTopic(String name) must be added to the interface. Right now the docs say similar methods on Session should not generally be used and JNDI lookup should be preferred, but this simply obscures the facts that application servers and JMS providers still need some API that lets them configure destinations. Putting the methods on the factory provides that common API.
Concerns
- Most
QueueandTopicimplementations provide a constructor that accepts the destination name as its only String parameter, so changes toConnectionFactoryare theoretically unnecessary, but constructors are not a part of the interface, so I'd prefer two trivial factory methods instead. If some vendors don't provide a compliant implementation, writing a wrapper will still be trivial. - Low demand for the change. MicroProfile Reactive Messaging is the new hip API, and vendors that provide cloud native Jakarta EE application servers might not be interested in changes that let customers migrate away from their software with ease.
An example of how this might look in practice:
@JMSConnectionFactoryDefinition(
name = "java:app/jms/Artemis",
className = "org.apache.activemq.artemis.jms.client.ActiveMQXAConnectionFactory"
interfaceName = "javax.jms.XAConnectionFactory",
user = "foo",
password = "bar",
properties = {
"brokerURL=tcp://example.com:61616"
}
)
@JMSDestinationDefinition(
name = "java:app/jms/SourceQueue",
interfaceName = "javax.jms.Queue",
destinationName = "FOO.BAR.ADAPTER",
connectionFactoryLookup = "java:app/jms/Artemis"
)
These declarations do not require a JCA resource adapter to work, but work with artemis-jms-client directly, which must be packaged with either the application or the application server.
Wouldn't it be an option to declare the whole annotation under a new name and deprecate the old ones to be removed (or moved to an optional module, if that was possible) in a future Jakarta EE version? Since the whole "JMS" term is subject to renaming and redefinition anyway.
This looks sensible. I would look at this alongside a modernized CDI based message listener.
Reza Rahman Jakarta EE Ambassador, Author, Blogger, Speaker
Please note views expressed here are my own as an individual community member and do not reflect the views of my employer.