[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

Generated at Mon Jul 14 08:39:13 UTC 2014 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.