jsr343-experts@jms-spec.java.net

[jsr343-experts] (JMS_SPEC-46) Define standard API to create and configure a ConnectionFactory

From: Nigel Deakin <nigel.deakin_at_oracle.com>
Date: Thu, 11 Aug 2011 16:46:12 +0100

I have created this JIRA issue
http://java.net/jira/browse/JMS_SPEC-46

Aspects of this issue were raised by both Clebert and Emran, but I believe there is a wider requirement which comes out
of the Java EE platform initiatative to allow JMS and other resources to be specified in more detail.

Clebert wrote: "[I would like to see the ability] to instantiate connection factories directly. I would make a relation
to JDBC here. You can make here an analogy to JDBC as you don't need JNDI to make an initial connection."

Emran wrote: "[I would like to see] API on connection factories to create connections with secure transport (I have seen
this feature in the jms containers as a configurable property on connection factories)."

This is quite a long description and it may be easier to read the formatted version in the JIRA issue rather than the
text version below. In any case, I would appreciate your comments on what is a small but potentially very significant
change.

Nigel


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

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 "Relevant sections of the JMS 1.1 Specification"
below).

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

* in a Java EE environment, there is no standard way of configuring the JMS requirements of a particular application

* it is inconsistent with way in which a JDBC DataSource objects is defined, both in a Java SE and a Java EE
environment. This is discussed more in 'How JDBC DataSource objects are configured'.

Proposals
---------

It is proposed that the way that a ConnectionFactory is created and configured be partially standardised in a manner
similar to JDBC DataSource objects, as follows:

* A ConnectionFactory implementation is a JavaBean, and may be instantiated by executing the no-arg constructor of its
implementation class. For example:

        ConnectionFactory cf = Class.forName("com.sun.messaging.ConnectionFactory")

* The JMS specification will define a set of properties which may be used to identify and describe a ConnectionFactory
implementation.

|| Property name || Type || Description||
| description | String | description of this connection factory|
| 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) |
| networkProtocol | String| network protocol used to communicate with the JMS provider |
| serverName | String| server name of the JMS provider |
| portNumber | String| port number of the JMS provider |
| networkProtocols | String[] | array of network protocols used to communicate with the JMS provider |
| serverNames | String[] | array of server names of the JMS provider |
| portNumbers | String[] | array of port numbers of the JMS provider |
| url | String| Opaque string which defines how to connect to the JMS provider |
| clientId | String| JMS client identifier |

* ConnectionFactory properties follow the convention specified for properties of JavaBeans components in the JavaBeans
1.01 Specification. ConnectionFactory implementations may augment this set with implementation-specific properties. If
new properties are added, they must be given names that do not conflict with the
standard property names.

* ConnectionFactory implementations must provide "getter" and "setter" methods for each property they support. These
properties typically are intended to be initialized before the object is bound in JNDI for subsequent use by an application.

* ConnectionFactory properties are not intended to be directly accessible by JMS clients. This design is reinforced by
defining the access methods on the implementation class rather than on the public DataSource interface used by
applications. Furthermore, the object that the client manipulates can be a wrapper that only
implements the ConnectionFactory interface. The setter and getter methods for the properties need not be exposed to the
client.

* Management tools that need to manipulate the properties of a ConnectionFactory implementation can access those
properties using introspection.

Note that this gives three alternative ways to define how the connection factory should communicate with the server:

* an opaque URL string

* a tuple of (networkProtocol, serverName, portNumber), where networkProtocol may be omitted

* an array of such tuples, represented here as three separate arrays

A JMS provider may support all, some or none of these alternatives.

* If both URL and one of the other forms are supported and both are supplied, the URL is used.

* If the single tuple (networkProtocol, serverName, portNumber) is supported, then a single-element array of tuples will
also be supported

(Much of the wording above is based on section 9.4.1 'DataSource properties' of the JDBC 4.0 specification.)

How JDBC DataSource objects are configured
------------------------------------------

This section describes how, although JDBC DataSource objects are similar in concept to JMS ConnectionFactory objects,
the JDBC and Java EE specifications define in much more detail how DataSource objects are created and configured than
the JMS specification defines for ConnectionFactory objects.

A JMS ConnectionFactory is a factory for creating connections to a JMS provider, using the createConnection method. In
JDBC, a javax.jdbc.DataSource fulfils a similar role as a factory for creating connections to a JDBC database, using the
getConnection method.

Section 9.4.2 recommends that javax.jdbc.DataSource objects are stored in JNDI to allow database-specific configuration
to be kept separate from the application. This much is similar to JMS.

However the JNDI specification differs from JMS in providing a lot of guidance on how to create a DataSource. Section
9.4.1 contains a whole list of standard data source properties which may be supported:

* databaseName
* dataSourceName
* description
* networkProtocol
* password
* portNumber
* roleName
* serverName
* user

Although the specification suggests that not all DataSource implementations support all properties, it does define names
for these most common properties, and specifies that when supported, they must be configurable using standard JavaBeans
"setters and getters".

In addition, a DataSource may be instantiated by invoking its no-arg constructor. This isn't stated explicitly in the
spec (if the DataSource were a JavaBean then a no-arg constructor would be mandatory, but the spec only states that its
properties follow the conventions specified for properties of JavaBeans, not that a DataSource is itself a JavaBean) but
in practice the convention that it can is well-established.

This means that a DataSource may be instantiated, given the name of the implementation class as a String, using code of
the following form:

        DataSource ds = Class.forName("oracle.jdbc.pool.OracleDataSource")

Meanwhile, the Java EE 6 specification defines a DataSourceDefinition annotation and a corresponding <data-source>
element which defines the following properties of a DataSource:

* className (required)
* name (required)
* databaseName
* description
* initialPoolSize
* isolationLevel
* loginTimeout
* maxIdleTime
* maxPoolSize
* maxStatements
* minPoolSize
* password
* portNumber
* properties
* serverName
* transactional
* url
* user

This is a longer list than is defined in JDBC, partly because the JDBC spec is older, but also because it also includes
pooling properties. Perhaps of the most interest is the url property, which may be provided as an alternative to
serverName and port.

Relevant sections of the JMS 1.1 Specification
----------------------------------------------

The relevant sections of the JMS specification are given below:

Section 2.3 'Administration'

"It is expected that JMS providers will differ significantly in their underlying messaging technology. It is also
expected there will be major differences in how a provider’s system is installed and administered.

"If JMS clients are to be portable, they must be isolated from these proprietary aspects of a provider. This is done by
defining JMS administered objects that are created and customized by a provider's administrator and later used by
clients. The client uses them through JMS interfaces that are portable. The administrator creates them using
provider-specific facilities.

"There are two types of JMS administered objects:

• "ConnectionFactory - This is the object a client uses to create a connection with a provider.
• "Destination - This is the object a client uses to specify the destination of messages it is sending and the source of
messages it receives.

"Administered objects are placed in a JNDI namespace by an administrator. A JMS client typically notes in its
documentation the JMS administered objects it requires and how the JNDI names of these objects should be provided to it.

Section 4.2 'Administered Objects'

"JMS administered objects are objects containing JMS configuration information that are created by a JMS administrator
and later used by JMS clients. They make it practical to administer JMS applications in the enterprise.

"Although the interfaces for administered objects do not explicitly depend on JNDI, JMS establishes the convention that
JMS clients find them by looking them up in a namespace using JNDI.

"An administrator can place an administered object anywhere in a namespace. JMS does not define a naming policy.

"This strategy of partitioning JMS and administration provides several benefits:

• It hides provider-specific configuration details from JMS clients.
• It abstracts JMS administrative information into Java objects that are easily organized and administered from a common
management console.
• Since there will be JNDI providers for all popular naming services, this means JMS providers can deliver one
implementation of administered objects that will run everywhere.

"An administered object should not hold on to any remote resources. Its lookup should not use remote resources other
than those used by JNDI itself.

"Clients should think of administered objects as local Java objects. Looking them up should not have any hidden side
effects or use surprising amounts of local resources.

"JMS defines two administered objects, Destination and ConnectionFactory.

"It is expected that JMS providers will provide the tools an administrator needs to create and configure administered
objects in a JNDI namespace. JMS provider implementations of administered objects should be both
javax.naming.Referenceable and java.io.Serializable so that they can be stored in all JNDI naming contexts. In addition,
it is recommended that these implementations follow the JavaBeans design patterns."