[JMS_SPEC-89] Define standard API to create and configure a ConnectionFactory in Java SE applications and by a Java EE container Created: 27/Mar/12  Updated: 30/Mar/12

Status: Open
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-underreview

 Description   

This is a proposal to extend the JMS specification to define a standard way of instantiating and configuring connection factory objects.

The proposal below is intended to be used by Java SE applications and by Java EE container code such as resource adapters, but not by Java EE applications themselves. This is not intended to provide an alternative to Java EE configuration via JNDI.

It replaces the proposal made in JMS_SPEC-46 and is being logged as a separate JIRA issue to avoid confusion.

Background

A connection factory is an example of an administered object. The JMS 1.1 specification establishes the convention whereby administered objects (connection factories and destinations) are not created in application code. Instead they are created by an administrator using tools specific to the JMS provider and stored in JNDI. The application code then looks up the connection factory or destination from JNDI and uses them in accordance with the JMS API.

The purpose of this is clearly stated in the specification: it is to allow everything that is non-standard and specific to a particular JMS provider to be kept out of the code itself. (See JMS 1.1 specification section 2.3 "Administration").

In the case of connection factories, this means that the application doesn't have to contain any information about how to connect to the JMS provider. For example, if the JMS provider is running on some remote server, the application doesn't contain any information about the location of the server or the protocol used to connect to it. All this information is defined when the connection factory is created by an administrator, separate from the application itself.

However the JMS specification says nothing about how the connection factory itself is created or configured, other than saying that it is done by "provider-specific facilities". All it says is that:

  • it must implement javax.jms.ConnectionFactory,
  • it must implement javax.naming.Referenceable and java.io.Serializable, so it can be stored in all JNDI naming contexts (section 4.2)
  • it is recommended that implementations "follow the JavaBeans design patterns"
  • it allows client identifier to be set (section 4.3.2)

However the specification does not define:

  • how a connection factory is instantiated
  • how the location of the server is defined
  • how client identifier is set
  • how other properties are set

Now although this omission from the JMS 1.1 specification is no doubt deliberate, it does cause some difficulties:

  • it is not possible to develop standard tools for creating connection factories (and binding them in JNDI) which work with multiple JMS providers
  • it means that a generic JMS resource adapter, which wraps the connection factories of third-party JMS providers, cannot instantiate those connection factories directly but must instead look then up from JNDI
  • it requires Java SE applications which use JMS to use JNDI as the only way to keep provider-specific configuration separate from their code. Applications cannot manage configuration their own way, such as by using properties files.

Proposed standard for instantiating a connection factory and setting properties

It is proposed that for Java SE applications, and for Java EE container code only, but not for Java EE applications, a ConnectionFactory can be instantiated and configured by invoking a constructor which takes a Properties object as an argument:

Properties props = new Properties();
props.setProperty("javax.jms.url","jms://localhost:1234"};
props.setProperty("javax.jms.user","admin"};
props.setProperty("javax.jms.password",password);
ConnectionFactory cf = new com.acme.jms.AcmeConnectionFactory(properties props);

Note that since properties are passed into the constructor rather than be set after the object has been created in order this allows connection factories to be implemented as immutable objects which cannot be changed after creation. That's why this proposal does not suggest setting properties directly on the connection factory.

(Another reason why this proposal does not suggest setting properties directly on the connection factory is that it would require changes to the javax.jms.ConnectionFactotry interface which would be inappropriate for connection factories in a Java EE environment.)

Even though this approach is intended to avoid the need to use JNDI it remains the goal of JMS to allow the creation of applications which are portable between JMS providers. This means that declaring provider-specific classes in the application is discouraged. Instead, a new utility class javax.jms.ConnectionFactoryCreator will be provided by JMS which allows the provider-specific connection factory class name to be passed in as just another property. This could be used as follows:

Properties props = new Properties();
props.setProperty("javax.jms.connectionFactoryClassName","com.acmejms.AcmeConnectionFactory"};
props.setProperty("javax.jms.url","jms://localhost:1234"};
props.setProperty("javax.jms.user","admin"};
props.setProperty("javax.jms.password",password);
ConnectionFactory cf = javax.jms.ConnectionFactoryCreator.create(properties props);

In the above example, the property values are hardcoded just to make the example clearer. However it would be recommended that they be defined separately from the application.

Why is this not proposed for Java EE applications?

Note that this proposal does not cover Java EE applications. This is because in the Java EE web and application container a connection factory cannot be created in isolation because it needs to participate in the connection pooling facilities of the container. The JCA API defines two methods on javax.resource.spi.ManagedConnectionFactory to create a connection factory: createConnectionFactory() and createConnectionFactory(ConnectionManager cxManager).

This also provides another reason why the above proposal passes properties to the connection factory constructor rather than allowing them to be set on the connection factory instance. If we had allowed the latter this would have added new methods to the Connectionfactory interface whose use we would have needed to explicitly disallow for Java EE applications.

Proposed standard properties:

The following standard properties may be used to configure the connection factory.

Property name Constant Type Description
javax.jms.user ConnectionFactoryCreator.USER String user name used when the connection factory method createConnection() (with no arguments) is called
javax.jms.password ConnectionFactoryCreator.PASSWORD String password used when the connection factory method createConnection() (with no arguments) is called
javax.jms.clientId ConnectionFactoryCreator.CLIENT_ID String clientId that will be used when a connection is created
javax.jms.url ConnectionFactoryCreator.URL String Opaque string which defines how to connect to the JMS provider. Whether this property is used, and what it is set to, is defined by the JMS provider.

This proposal deliberately keeps the list of standard properties to a bare minimum, and abandons the longer list proposed in JMS_SPEC-46. It is expected that JMS providers will define their own additional properties.

The following standard property must always be supplied to the ConnectionFactoryCreator create method in addition to any of the properties specified in the previous table:

Property name Constant Type Description
javax.jms.connectionFactoryClassName ConnectionFactoryCreator.
CONNECTION_FACTORY_CLASS_NAME
String Class name of connection factory





[JMS_SPEC-47] Deprecate domain-specific APIs and propose for removal Created: 15/Aug/11  Updated: 24/Feb/12

Status: Open
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: eg, pd20-underreview

 Description   

Summary

In version 1.0b of the JMS specification, applications had to use a completely separate set of interfaces when working with queues as they did when working with topics.

Specifically, applications working with queues had to use the interfaces QueueConnectionFactory, QueueConnection, QueueSession, QueueSender and QueueReceiver, whilst applications working with topics had to use the interfaces TopicConnectionFactory, TopicConnection, TopicSession, TopicPublisher and TopicSubscriber.

Although these two sets of interfaces shared common supertype interfaces ConnectionFactory, Connection, Session, MessageProducer and MessageConsumer, these were effectively abstract classes, and applications were forced to use the interfaces specific for the messaging domain (queue or topic) that they were using.

In version 1.1, new API methods were added to the common superclass, domain-independent, interfaces to allow them to be used directly by client applications. This offered a simpler programming model, and for first time allowed queues and topics to participate in the same local transaction, now that they could be accessed using the same session.

In JMS 1.1 all of the domain-specific interfaces were retained to provide backwards compatibility, but it was stated in Section 1.5 that "in the future, some of the domain-specific APIs may be deprecated".

For 2.0 it is time to take this to the next stage, and to formally announce that these interfaces are now deprecated and that they will be removed from a future version of the specification.

This would remove 15 interfaces from JMS and reduce the total number of interfaces by 34%, from 44 to 28.

Detail

This change would affect the following interfaces:

XAQueueConnection
XAQueueConnectionFactory
XAQueueSession
XATopicConnection
XATopicConnectionFactory
XATopicSession
QueueConnection
QueueConnectionFactory
QueueReceiver
QueueSender
QueueSession
TopicConnection
TopicConnectionFactory
TopicPublisher
TopicSession
TopicSubscriber

There would be two changes:

  • These interfaces would be formally marked as deprecated, by use of the @java.lang.Deprecated annotation. This would cause compilers to issue a warning when a deprecated method was used.
  • These interfaces would be formally marked in the specification as being "proposed for removal", with the expectation that they would be made optional in the next release.

There do not appear to be any binding policies on how to deprecate or remove classes from a Java EE API, which means that the final decision is up to the expert group. However the Java EE Specification, section EE.6.1.3 "6.1.3Pruned Java Technologies" (which discusses a different issue, that of removing entire technologies from Java EE), links to a Java SE policy described at http://mreinhold.org/blog/removing-features, which appears to be a suitable policy to offer.

That policy states that a particular version of a spec may state that a feature is "proposed for removal". This means that the following version can remove it.

However that policy also states that "removal" of a feature does not mean actually deleting it. Instead the feature will remain in the specification but will become optional. This means that implementers are not required to implement it. Its tests will remain in the TCK to allow those who decide to implement it to verify that it has been implemented correctly.

Other issues

Before making this change we should confirm that the "domain-independent" interfaces are a complete replacement for the "domain-specific" interfaces.

It has been noticed that Session.createDurableSubscriber() returns a TopicSubscriber, not a MessageConsumer. This looks to me like a mistake which would need to be fixed before we could remove TopicSubscriber. The solution would be for this method to return a MessageConsumer. Since this is a supertype of TopicSubscriber it should not break existing applications. (Edit: This has now been raised separately as JMS_SPEC-51 )






[JMS_SPEC-41] Support topic hierarchies Created: 05/Aug/11  Updated: 08/Jan/13

Status: Open
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: Improvement Priority: Major
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: pd20-underreview

 Description   

This issue was raised by a member of the JSR 343 Expert Group and is logged here to allow the issue to be discussed and tracked.

It is proposed that the JMS specification supports "topic hierarchies". These are also known as subject hierarchies or wildcard subscriptions.

The JMS 1.1 specification states that a topic is a "well-known node in a content-based hierarchy" but does not specify how this hierarchy is used, how topics are named, or define any special functionality to operate on more than one node of the hierarchy at the same time.

It is proposed that new features are added to JMS to explicitly support the use of topic hierarchies. More detailed proposals will follow: this JIRA issue is a placeholder.

Most JMS vendors and (and other pub/sub products) already support topic hierarchies, and they are integral to a variety of standards, including AMQP, Web Services Event Notification, and the Bayeaux protocol. They provide an intuitive solution for optimized message filtering, routing, and replication. Support for topic hierarchies would also be helpful for simplifying the integration of JMS applications into messaging environments that already depend on topic hierarchies.



 Comments   
Comment by axel_podehl [ 08/Jan/13 ]

I would think it'll be difficult and cumbersome to specify and use a provider-unspecific topic hierarchy. The ways wildcards actually work with different JMS providers are more diverse than you would initially think (or hope).

E.g. MQSeries Topics:

"Sport/#/Results" matches "Sport/Football/Spurs/Results"
while
"Sport/+/Results" only matches "Sport/Football/Results"
but also
"Sport/#" matches "Sport"

with TIBCO EMS and ActiveMQ, separators (. instead of /) and wildcards are different,
but also their meaning:

"Sport.>.Results" is invalid
"Sport.*.Result" would work as well
"Sport.>" does not match "Sport"

Also leaving it up to individual providers on how exactly topic names or hierarchies work is a great differentiator, leaving room for innovation. A simple String as topic name can be used to define additional properties of a topic on the fly, e.g. in ActiveMQ: "temp-queue://TEST?consumer.prefetchSize=10"

Nice-to-have though, when writing provider-unspecific code, would be these methods:

public boolean Destination.isWildcard()
public boolean Destination.isMatching(String wildcard)





[JMS_SPEC-28] Clarify how the JMS provider should interact with Transaction Managers. Created: 06/Jul/11  Updated: 24/Feb/12

Status: Open
Project: jms-spec
Component/s: None
Affects Version/s: 1.1
Fix Version/s: None

Type: Improvement Priority: Critical
Reporter: Nigel Deakin Assignee: Unassigned
Resolution: Unresolved Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: eg, pd20-underreview

 Description   

Clarify how the JMS provider should interact with Transaction Managers. In particular, the responsibilities of the JMS Provider, the TM and the App Server during recovery need to be clearly defined.

(This issue is a placeholder. More information about the ambiguities that need to be resolved will be added later)



 Comments   
Comment by cptmauli [ 06/Dec/11 ]

Please provide a way to specify explicitly when a JMS Message is sent.

Current situation (for instance JBoss 6, but others have the same problem):

  • a method updates the database and sends a JMS message (transactional)
  • the message is received and the same record is read from the database, but it will often still read the state before the update

Cause:

the JMS message is sent when the transaction manager decides that the commit is valid. That doesn't mean the actual database commit is now visible! This hurt us badly and we had to use the TransactionSynchronizationRegistry to work around this issue.

Solution:

The ideal solution would be if I could define the way when the message should be sent, I also would like to see that even beeing within a Transaction that I have the means to send a message non-transactional. Further it also should provide a way to send a message if a rollback occurs. A enum in the send method would be nice, something like NON_TRANSACTIONAL, DEFAULT, ON_COMMIT, ON_ROLLBACK, AFTER_COMMIT.

Comment by Nigel Deakin [ 08/Dec/11 ]

Can you explain the issue in more detail? You write

> the JMS message is sent when the transaction manager decides that the commit is valid.

It's up to the JMS provider to decide when to actually send the message from the producing client to the JMS server. It's fine to sent it immediately (when the application calls MessageProducer.send()). When the JMS server receives the message it can add it to the queue or topic but (assuming we're in a Java EE transaction) must not commit the operation.

> That doesn't mean the actual database commit is now visible!

When the transaction on the client is committed, the transaction manager will call commit() on the XAResource object provided by the JMS client. The JMS client will send the commit to the JMS server which will then commit the previous addition of the message to the queue or topic. The message will then become available for delivery to consumers.

> This hurt us badly and we had to use the TransactionSynchronizationRegistry to work around this issue.

Please provide more information to allow us to understand the problem.

Comment by Leos.Bitto [ 14/Dec/11 ]

> When the transaction on the client is committed, the transaction manager will call commit() on the XAResource object provided by the JMS client. The JMS client will send the commit to the JMS server which will then commit the previous addition of the message to the queue or topic. The message will then become available for delivery to consumers.

The problem is that after the message becomes available for delivery to the consumers, some consumer might start processing it and find old information in the database (for some record(s) identified by the data in the JMS message), because the commit() on the relevant database XAResource has not been processed yet (because it is processed after commit() of the JMS XAResource).

Some transaction managers allow ordering of the calls to commit() of the XAResources enlisted in the transaction, but this is an optional extenstion which is not required by JTA. See http://docs.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/5/html/Transactions_Development_Guide/chap-Transactions_JTA_Programmers_Guide-Test.html#form-Transactions_JTA_Programmers_Guide-The_XAResource_Interface-Extended_XAResource_control for example. With the TransactionManager implementation from JBoss the possible workaround is to use the JMS XAResource wrapper which implements com.arjuna.ats.jta.resources.EndXAResource and therefore ensures that when the JMS message is sent, all the relevant database operations are already committed.

I am not sure whether this can be solved in JMS 2.0 only, though. It seems that this would require some cooperation from the JTA specification as well.

Comment by Nigel Deakin [ 14/Dec/11 ]

> The problem is that after the message becomes available for delivery to the consumers,
> some consumer might start processing it and find old information in the database
> (for some record(s) identified by the data in the JMS message),
> because the commit() on the relevant database XAResource has not been processed yet
> (because it is processed after commit() of the JMS XAResource).

The commit won't happen until onMessage() has returned, so how does the order in which the two resources in the transaction are committed make any difference?

Comment by Leos.Bitto [ 14/Dec/11 ]

1. onMessage() is called for processing of the JMS message #1
2. in onMessage() some data is updated in the database, based on the identification of this data from the JMS message #1
3. in onMessage() a JMS message #2 is sent, including the the identification (only a key, not the whole data) of the modified data in the database
4. onMessage() returns
5. XAResource#prepare is called for both the JDBC and JMS XAResources (the order is irrelevant)
6. XAResource#commit is called for the JMS XAResource, which removes the JMS message #1 from its queue, and sends the JMS message #2 to another queue
7. onMessage() is called in another thread for processing of the JMS message #2
8. data from the database is read, based on the data in the JMS message #2
9. problem is here - old data is read from the database!
10. in the original thread, XAResource#commit is called for the JDBC XAResource, which persists the updated data in the database, but it is too late now - another thread read wrong data already

Comment by Nigel Deakin [ 14/Dec/11 ]

I understand now. Thanks for the clarification.

This seems to be a general issue with the two-phase commit of two resources, where the updates to one resource are dependent on the updates to the other. As you suggested, this doesn't sound like something that can be tackled at the level of an individual resource manager such as JMS. It might be worth raising it with the Java EE 7 Platform Expert Group.

Comment by Leos.Bitto [ 15/Dec/11 ]

I am not sure whether this is the proper way of raising it, but here you are: http://java.net/jira/browse/JAVAEE_SPEC-1

Comment by Nigel Deakin [ 15/Dec/11 ]

That seems a good way to start (I note this is the first issue!).

I'll ping the Java EE spec leads to check they see it.

Any discussions on this will be automatically copied to, or take place on, the users' mailing list for that project so I would suggest subscribing there if you want to follow this up.





[JMS_SPEC-26] Decide on the future of the optional Chapter 8 API "JMS Application Server Facilities" Created: 06/Jul/11  Updated: 24/Feb/12

Status: Open
Project: jms-spec
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Improvement Priority: Critical
Reporter: Nigel Deakin Assignee: Nigel Deakin
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: eg, pd20-underreview

 Description   

Chapter 8 of the JMS 1.1 specification, "JMS Application Server Facilities", defines an API for use by application servers. It has two parts:

  • API to allow concurrent processing of a subscription's messages: the interfaces ServerSession, ServerSessionPool, ConnectionConsumer and the methods Session.setMessageListener(), Session.getMessageListener() and Session.run().
  • API to support distributed (XA) transactions: XAConnectionFactory, XAConnection and XASession.

This API is optional and has no compliance tests.

Should this API be made mandatory, like the rest of the JMS spec, or should it be formally pruned from the spec?

This will partly depend on the outcome of http://java.net/jira/browse/JMS_SPEC-25 (Standardise the interface between a JMS provider and a Java EE application server). If it is decided that the interface between a JMS provider and a Java EE application server should use these interfaces (rather than the Java EE Connector API) then clearly they should become mandatory.

However, irrespective of the outcome of http://java.net/jira/browse/JMS_SPEC-25 it may be beneficial to keep this API and make it mandatory since that would

1. allow the creation of a generic JMS resource adapter that can work with any JMS 2.0 implementation, and
2. allow the creation of non-Java EE frameworks that provide services such as XA transactions and async delivery to multiple consumers, but which don't support the Java EE Connector Architecture

However these potential benefits need to be offset against the additional burden this may place on JMS vendors.

Note that if it is decided that these interfaces are not needed, they would not be deleted from the spec but remain in their current optional state, in accordance with chapter EE.6.1.3 "Pruned Java Technologies" of the Java EE 6 specification, perhaps with an explicit statement of why they are not needed.

If it is decided that these interfaces are still required then there some improvements may be required to clarify, say, the integration with the transaction manager.



 Comments   
Comment by Nigel Deakin [ 26/Jan/12 ]

It would be worth updating the Javadoc for the optional Chapter 8 API to explain that these classes and methods are primarily intended for use by application servers. This is obvious to anyone reading the spec, but for some reason isn't spelled out in the javadoc for methods like Session.setMessageListener().

Comment by Nigel Deakin [ 16/Feb/12 ]

I asked a colleague for their comments on the Chapter 8 API, and they replied as follows:

The getXAResource call has proved relatively robust for directly integrating foreign providers like Tibco, Sonic, and IBM MQ.

I think the main issue I have with it is the multi-RM problem: correctly fronting a logical RM that's actually backed by an independent set of RMs. In particular the problem is that we must currently somehow return the entire set of in-doubt transactions for all RMs in an entire cluster when "XAResource recover()" is called, even for component RMs that may not be running. We've all already discussed this at length. Currently, each provider must come up with some sort of internal solution on its own - but this isn't easy. Advancing one or all of the JTA, JCA, or JMS specs would help...

Another relatively smaller problem is that it would help to know when a vendor has thread-affinity requirements for a transaction life-cycle on the XAResource (IBM MQ). Or, alternatively, to harden the spec so that it's illegal to require thread affinity by default. It's a bit painful for a container to enforce such a requirement.

A secondary issue is the ConnectionConsumer API. It is complex and it's not entirely clear how it's supposed integrate with a foreign TM, and we've found no strong need to make use of it when integrating foreign providers.





Generated at Sun Aug 30 06:04:58 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.