jsr343-experts@jms-spec.java.net

[jsr343-experts] (JMS_SPEC-89) Define standard API to create and configure a ConnectionFactory in Java SE applications and by a Java EE container

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Tue, 27 Mar 2012 11:05:07 +0100

I have logged this JIRA issue:
http://java.net/jira/browse/JMS_SPEC-89

This replaced JMS_SPEC-46 which I have withdrawn and closed.

Description follows (this is best viewed in JIRA). Comments please.

Define standard API to create and configure a ConnectionFactory in Java SE applications and by a Java EE container
------------------------------------------------------------------------------------------------------------------

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.

h4. 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:

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

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:

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

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 connection factory properties are proposed:

Property name Type Description
user String user name (may be overridden when createConnection is called)
password String password corresponding to user name (may be overridden when createConnection is called)
clientId String clientId that will be used when a connection is created
url String Opaque string which defines how to connect to 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.