users@jms-spec.java.net

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

From: John D. Ament <john.d.ament_at_gmail.com>
Date: Tue, 27 Mar 2012 11:43:56 -0400

Nigel,


On Tue, Mar 27, 2012 at 11:28 AM, Nigel Deakin <nigel.deakin_at_oracle.com>wrote:

> John,
>
>
> On 27/03/2012 14:56, John D. Ament wrote:
>
> Nigel,
>
> So a few things. I guess I made the assumption that create == retrieve.
> I suppose there could be a difference - for example, looking up via JNDI
> gives you a remote object reference, but instantiating the connection
> factory in activemq is creating the implementation of connection factory.
> When I was using getReference, it was really pointing out that it could be
> either - a remote object or an actually instantiated object. This could be
> vendor specific.
>
> Ah, I see. I think whether the connection factory is a "remote object
> reference" is an implementation detail (it certainly isn't one in the cases
> I am familiar with). The object might be stored in JNDI as a Reference, but
> that reference will be turned back to a ConnectionFactory instance when it
> is looked up.
>
> (But we're just discussing the name of a method here)
>


At least from my perspective, the name of the method implies something
about what the method is doing. create methods usually create something,
something like getReference would leave ambiguity to the implementer on
whether it's creating a new object or looking it up via a remote JNDI
connection. From my very recent experience, I would say that the weblogic
implementation would probably provide only a remote object (though in no
way am I speaking for oracle here).

John



>
> See below for the rest.
>
>
> Ditto.
>
>
>
> John
>
> On Tue, Mar 27, 2012 at 6:59 AM, Nigel Deakin <nigel.deakin_at_oracle.com>wrote:
>
>> John,
>>
>> Thanks for the quick feedback!
>>
>>
>> On 27/03/2012 11:45, John D. Ament wrote:
>>
>> My feedback would be that the API should be more like:
>>
>> 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 = javax.jms.ConnectionFactories.getReference(props);
>>
>>
>> I made a careless error in my proposal: I wrote:
>>
>> ConnectionFactory cf = new javax.jms.ConnectionFactoryCreator(properties props);
>>
>> which doesn't make sense. I meant to write:
>>
>> ConnectionFactory cf = javax.jms.ConnectionFactoryCreator.create(properties props);
>>
>> which is identical to your proposal except that you've suggested a
>> different class and method name (I don't have strong views about that).
>>
>> I've corrected the JIRA issue.
>>
>> Why do you suggest "getReference"? I see this method as creating a new
>> object (a connection factory), whereas you appear to be thinking of it
>> differently.
>>
>>
>>
>> I would prefer a cleaner API though - either an equivalent getReference
>> that took in the actual values, or took in a Map.
>>
>>
>> Properties implements Map. However I think Properties is better because
>> these it expects keys and values to be Strings, which is what I think is
>> appropriate here (e.g. it allows properties to be read from a file or
>> configured in a GUI)
>>
>>
>>
>
> Right, Properties implements Map (and extends Hashtable, thus requiring it
> to be synchronized). Ideally, I would expect the argument to be
> Map<String,Object>, or Map<String,String> which could be a properties
> file. Note that properties is actually <Object, Object> type, harming some
> of the type safety.
> http://docs.oracle.com/javase/7/docs/api/java/util/Properties.html
>
>
>
>
> Yes, I like that. Map<String,String> would indeed be better.
>
>
> I would also prefer if we really needed the connectionFactoryClassName
>> (which, I would think we don't really need) that it could be an actual
>> class, not a string.
>>
>> If you have the class declared in the application then you can simply
>> use its constructor, which is defined in the first part of the proposal.
>>
>> 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);
>>
>>
> So would it be a new requirement that the constructor supports an argument
> of properties or Map (as I am pushing above).
>
>
> Yes, that is what I am proposing.
>
> Nigel
>
>
>
>> Nigel
>>
>>
>> John
>>
>>
>> On Tue, Mar 27, 2012 at 6:05 AM, Nigel Deakin <nigel.deakin_at_oracle.com>wrote:
>>
>>> 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.
>>>
>>>
>>>
>>
>