jsr343-experts@jms-spec.java.net

[jsr343-experts] Re: [jms-spec users] Re: JMS Support for DI

From: John D. Ament <john.d.ament_at_gmail.com>
Date: Tue, 30 Aug 2011 20:13:43 -0400

Reza,

On Tue, Aug 30, 2011 at 8:01 PM, Reza Rahman <reza_rahman_at_lycos.com> wrote:

> John/Nigel,
>
> * JMS would end up providing an extension, perhaps we would require some
> special notation somewhere (e.g. in beans.xml or something) to denote when
> JMS should be activated against the bean archive.
> - I don't think this necessarily needs to be a CDI portable extension per
> se - that's more of an implementation detail. In fact, in Resin's case, it
> would be part of it's JMS 2 implementation/core Java EE container that is
> not pluggable at all. For other containers, it could be implemented
> completely independent of CDI. That would really be the value of sticking to
> the JSR 330 annotations.
>

If we're trying to also standardize the resource adapter between JMS and an
EE container, it's a bit hard for me to accept a non standardized way to
ensure that JMS 2.0 CDI support were enabled by default.


>
> * My point here is that we don't want to reduce the features currently
> available to developers who use @Resource. I'll try to find out more about
> how we might do that.
> - We should confirm this with the platform EG, but I don't think not
> supporting @Resource.name/_at_Resource.mappedName is a big issue. I think we
> are trying to deprecate that in favor of global JNDI names anyway. If this
> is indeed an issue, we could specify @Resource as being nested as a
> parameter of @JmsConnection, etc.
>
> Cheers,
> Reza
>
>
>
> On 8/30/2011 7:13 PM, John D. Ament wrote:
>
> Nigel,
>
> Comments are below. Wanted to think about this for a while before
> responding.
>
> On Fri, Aug 19, 2011 at 7:40 AM, Nigel Deakin <nigel.deakin_at_oracle.com>wrote:
>
>> John,
>>
>> I'm responding to the specific issues where I have a ready response..
>> (Others may require more thought).
>>
>>
>> On 19/08/2011 02:48, John D. Ament wrote:
>>
>> Nigel,
>>
>> Thanks for the comments. My responses are in line.
>>
>> - John
>>
>> On Thu, Aug 18, 2011 at 10:31 AM, Nigel Deakin <nigel.deakin_at_oracle.com>wrote:
>>
>>> John,
>>>
>>> I have an assortment of questions and comments here, some minor, others
>>> more major.
>>>
>>> But before I go through those I'd like to say that I think this document
>>> is exactly the kind of thing I had in mind when suggesting a user-friendly
>>> annotation-based layer on top of the JMS API.
>>>
>>> I think that your separating out "event messaging" into a separate
>>> proposal has helped a lot. The API you're proposing is still very
>>> recognisably JMS and doesn't divert us into discussing new programming
>>> models such as events.
>>>
>>> However I still think there a lot of questions that need to be asked. I'm
>>> sure you'll have answers ready for many of them!
>>>
>>> 1. AtInject
>>> -----------
>>>
>>> Let's start with a minor point. You call this "JMS Support for AtInject"
>>> . We probably want to put that the other way round!
>>>
>>> Also, is "AtInject" an official name for JSR 330? The Java EE 6 spec
>>> calls it "Dependency Injection for Java specification (JSR-330)"
>>>
>>> I'm a little bit vague about where DI (JSR 330) ends and CDI (JSR 299)
>>> starts, so it might be helpful if you gave us an overview of the differences
>>> as you see them.
>>>
>>> Your first assumption is "1. CDI 1.1 will support a bootstrap API for SE
>>> environments.". Does this mean that you're assuming a JSR 299 environment,
>>> not a purely JSR 330 one? Would there be any benefit in requiring "just" DI
>>> support rather than CDI support?
>>>
>>> With "just" DI, do we still have automatic creation of injected resources
>>> when they go into scope, and automatic closing of these resources when they
>>> go out of scope? What scopes are available, and what do they mean?
>>>
>>> (I appreciate some of these are standard questions. Perhaps as we develop
>>> the specification we should also work on a tutorial which would allow users
>>> to make use of these new features without needing to open the DI or CDI
>>> specs or manuals.
>>>
>>
>>
>> JSR-330 is typically considered “@Inject” or just “AtInject,” where as
>> the original “WebBeans” spec is simply JSR-299 or CDI. Obviously CDI works
>> better long term since it's JSR-346 in EE7. Referring to it as under
>> AtInject simply states that the JSR-330 annotations are enough to define the
>> DI behavior, making the API compatible with any JSR-330 implementation, and
>> supporting frameworks like Spring, Guice natively. As far as the
>> terminology, we are providing JMS capabilities to a CDI/AtInject module, so
>> I'm not sure if I'm missing your point ( I figure I am, since I don't see
>> what's wrong with the name, reading it the other way it makes me think that
>> CDI components can be injected into the JMS components, but that will likely
>> not be the case here )
>>
>> Based on what I put in, I believe the only requirement is AtInject,
>> but obviously it would be up to the implementor to provide managing of the
>> objects. Object management would only apply to CDI implementations. Nice
>> call out about scoping. My current assumption is that everything is
>> dependent scoped, where the life cycle of the injected component is tied to
>> the injection point. The choices are Dependent, RequesetScoped (bound to
>> HTTP request), SessionScoped (bound to HTTP session), ApplicationScoped
>> (bound to the lifecycle of the application), or Singleton (one per
>> application; but “application” needs to be clarified in the CDI spec for
>> these two).
>>
>>
>>
>>
>>>
>>> 2. Support in Java EE
>>> ---------------------
>>>
>>> The Java EE 6 specification, section EE.5.20 "Support for Dependency
>>> Injection (JSR-330)" defines the extent of support for JSR 330 required in a
>>> Java EE container. Are there any limitations there which would affect your
>>> proposal?
>>>
>>> In Java EE, would the application need to confirm to any conventions
>>> (like having a beans.xml) to allow it to use this API?
>>>
>>
>> Injection is supported into bean archives only, as defined by the CDI spec
>> - if beans.xml is found then the archive is scanned.
>>
>>
>> So we would expect, say, a servler or session bean to supply a beans.xml
>> file.
>>
>> - if a CDI extension is found, then it may manually add components.
>>
>>
>> Is this invisible to the application?
>>
>>
> Both of these require a deeper understanding of CDI. In most cases, the
> application will just provide a beans.xml in the archive to denote that this
> is a bean archive. Bean archives are scanned for AtInject and CDI support.
> Providing an extension is more framework level. JMS would end up providing
> an extension, perhaps we would require some special notation somewhere (e.g.
> in beans.xml or something) to denote when JMS should be activated against
> the bean archive.
>
>
>>
>>
>> I need to look a bit further to see if library scanning only applies to
>> beans.xml or if anything with a CDI extension is also scanned. I believe
>> this is one of the open questions currently, since it seems to be managed
>> differently for each app server.
>>
>>>
>>> 3 Implicit conversion of payload to message types:
>>> --------------------------------------------------
>>>
>>> You suggested that support the automatgic conversion of certain common
>>> classes and types to JMS message types:
>>>
>>> byte[], Byte[] => BytesMessage
>>> InputStream => StreamMessage
>>> CharSequence, char[], Character[] => TextMessage
>>> Map, and any implementation of => MapMessage
>>> Otherwise, an ObjectMessage is used.
>>>
>>> I think we should definitely discuss this, but since most of this
>>> document isn't actually dependent on implicit conversion we can afford to
>>> consider it as being slightly separate.
>>>
>>> "Implicit conversion" would require either some new factory methods to
>>> create messages, or new methods on the existing interfaces.
>>>
>>> I think allowing applications to avoid having to create an ObjectMessage
>>> to send an Object (Serializable, actually), or a TextMessage to send a
>>> String, is a nice idea, but I'm less sure about BytesMessage, MapMessage and
>>> StreamMessage.
>>>
>>> Note that an ObjectMessage sends a Serializable, not an Object.
>>>
>>> A TextMessage has a String as its payload, not a CharSequence (which is
>>> an interface implemented by String). Were you thinking of calling
>>> CharSequence.toString() and using that as the payload of a TextMessage, or
>>> were you thinking of a new JMS message type? If the latter then I think it
>>> is misleading to accept a CharSequence only to convert it to a String, and
>>> it would be clearer to expect any payload to be provided as a String.
>>>
>>> A BytesMessage has numberous methods to allow Ints, Floats etc to be
>>> written directly to the message (and vice versa). This allows vendors to
>>> optimise the implementation, especially when using very large messages and
>>> message compression. If we expected clients to assemble a separate byte[]
>>> and then copy it to a BytesMessage we would be forcing a potentially large
>>> object to be copied, and prevent vendor optimisations (like only
>>> decompressing a message when the client actually tried to read it).
>>>
>>> The same point applies to StreamMessage and MapMessage.
>>>
>>
>> My thinking was that there would be a new method (one only) to
>> MessageProducer that took an Object (java.util.Map is not Serializable,
>> which is why I say Object not Serializable). This object would be compared
>> to CharSequence, Serializable, etc. For CharSequence, yes, I was thinking
>> about using the toString representation to convert, since it is required in
>> the CharSequence interface.
>>
>>
>> Aren't we abandoning type safety by having a single method that took an
>> Object?
>>
>> I think it's important for the sender to be able to be certain about what
>> message type will be used, since the receiver will typically be written on
>> the assumption that messages for a particular purpose will be of a
>> particular type.
>>
>
>
> The problem I have though is that String implements Serializable. Maybe we
> just need separate method names, that take Serializable or String as
> arguments.
>
>
>>
>> I agree about the notes about the other message types. My point is that
>> for very simple cases it should be possible to send basic types with
>> implicit conversion to the mapped message types. I agree that this isn't
>> dependent on DI, but was something I wanted to raise. If it makes more sense
>> to discuss separately, we can move that discussion.
>>
>>
>>
>> Perhaps we could get 90% of the cases by providing
>> createMessage(Serializable s), which returns an ObjectMessage, and
>> createMessage(String s) which returned a TextMessage
>>
>> My remark about this being "slightly separate" is that changes to the
>> underlying API need to be be considered more widely, since they would
>> benefit/affect users who aren't using injection. I'm not trying to stop us
>> discussing it here for now.
>>
>>
>>
>>> 4. Injecting a connection
>>> -------------------------
>>>
>>> You suggest
>>>
>>> @Inject @JmsConnection(factory="foo")
>>> Connection connection;
>>>
>>> The attribute "factory" here is inconsistent with the use of the
>>> attribute "value" for @JmsDestination, both of which are intended to be the
>>> JNDI name of an administered object.
>>>
>>> However in Java EE applications can already use
>>>
>>> // JNDI name of resource
>>> @Resource (name="foo")
>>> Connection connection;
>>>
>>> // Name of resource
>>> @Resource (lookup="foo")
>>> Connection connection;
>>>
>>> // A product specific name that this resource should be mapped to.
>>> @Resource (mappedName="foo")
>>> Connection connection;
>>>
>>> The differences between these three ways to define a resource are defined
>>> in the Java EE spec.
>>>
>>> We would need to make sure that @Inject @JmsConnection could make use of
>>> all these different ways to access resources. I think having a single
>>> "factory" attribute may be insufficient to reflect the richness of the ways
>>> that resources can be obtained in Java EE.
>>>
>>
>> So part of the issue is that @Resource is not a qualifier, if it were the
>> issue is moot mostly. I use factory to indicate the ConnectionFactory, and
>> the attribute can be renamed to clarify. I can't find anything indicating
>> that you can inject a javax.jms.Connection using @Resource.
>>
>>
>> My point here is that we don't want to reduce the features currently
>> available to developers who use @Resource. I'll try to fnd out more about
>> how we might do that.
>>
>
> I don't know that this would. Wouldn't ConnectionFactories still be
> available via @Resource ? My assumption is that unless we are explicitly
> say " JMS will not do X anymore" then JMS is still doing it.
>
>
>>
>>
>>
>>>
>>> 5. Injecting a session (1)
>>> -------------------------
>>>
>>> @Inject @JmsConnection(factory="foo", acknowledgeMode=ClientAcknowledge)
>>> Session session;
>>>
>>> How would you create a (local) transacted session? (in the Java SE case)
>>>
>>> In http://java.net/jira/browse/JMS_SPEC-45 I propose a new method which
>>> combines the transacted and acknowledgeMode parameters in a single
>>> sessionMode parameter:
>>>
>>> Session createSession(int sessionMode) throws JMSException
>>>
>>> So for consistency, the annotation should be
>>>
>>> @Inject @JmsConnection(factory="foo", sessionMode=ClientAcknowledge)
>>> Session session;
>>>
>>> @Inject @JmsConnection(factory="foo", sessionMode=Transacted)
>>> Session session;
>>>
>>
>> I do want to get alignment between my proposed annotation and your
>> proposed change to support transacted and non-transacted clearer. Could your
>> spec change perhaps use an enum to describe the sessionMode as well?
>>
>>
>> Good idea.
>>
>>
>>
>>
>>>
>>> 6. Injecting a session (2)
>>> --------------------------
>>>
>>> You don't say anything about the relationship between connection and
>>> session objects.
>>>
>>> Would each session have its own connection, to satisfy Java EE
>>> requirements? Would there be a switch somewhere which told the
>>> implementation that Java EE restrictions were in force?
>>>
>>> In Java SE, where multiple sessions could use the same connection, when
>>> you injected a new session, how would the runtime decide whether to re-use
>>> an existing connection (if there were one with the same connection factory,
>>> user and password) rather than create a new one?
>>>
>>
>> Assuming dependent scope, each session would result in a new connection,
>> regardless of SE or EE.
>>
>>
>>
>>>
>>> 7. Injecting a destination
>>> --------------------------
>>>
>>> You propose
>>>
>>> @JmsDestination(value="foo")
>>>
>>> I note that this is a qualifier for use when injecting MessageConsumer
>>> and MessageProducer objects. You wouldn't inject a Destination directly. I
>>> like that.
>>>
>>> The attribute "value" here is inconsistent with the use of the attribute
>>> "factory" for @JmsConnection, both of which are intended to be the JNDI name
>>> of an administered object.
>>>
>>> However in a Java EE environment the same issues regarding names applies
>>> for this as for connection factories. We would need to make sure that users
>>> can supply the equivalent of name, mappedName or lookup.
>>>
>>
>> I think value should be overloaded, to try resolution by mappedName, name
>> or lookup depending on what is found first. However, underneath the
>> destination would typically be resolved via InitialContext.lookup rather
>> than injecting a resource, so I'm not sure we can support this fully.
>>
>>
>> This is the same point as I raised for @JmsConnection.
>>
>> I'm not sure about your idea of merging name,lookup and mappedName in a
>> single attirbute. If this is a desirable feature it is something that should
>> be defined at Java EE level rather than us offering something different for
>> JMS only.
>>
>
> At least from what I've seen, anytime you're dealing with an embedded JMS
> implementation (still haven't gotten OpenMQ yet, btw!) you have a customer
> way to look up destinations.
>
>
>>
>>
>>
>>> 8. Using a MessageConsumer/MessageProducer
>>> ------------------------------------------
>>>
>>> How would local transactions work? In particular, how would a application
>>> create, say, a consumer and a producer on the same session, receive a
>>> message, send a message, and then commit the session?
>>>
>>
>> This really depends on a decision around scope. If we choose to keep it
>> as dependent, then this couldn't happen, unless the object injected is a
>> session, and the consumer/producer are created in a post construct method,
>> e.g.:
>>
>> @RequestScoped
>> @Named("messageSender")
>> public class MessageSender {
>>
>> @Inject @JmsConnect(factory="/ConnectionFactory", transacted = true)
>> Session session;
>>
>> private MessageConsumer msgConsumer;
>> private MessageProducer msgProducer;
>>
>> @Resource(mappedName="jms/FooDestination") Destination d;
>>
>> @PostConstruct
>> public void init() {
>> msgProducer = session.createProducer(d);
>> msgConsumer = session.createConsumer(d);
>> }
>>
>> }
>>
>>
>> OK. This is also what users would need to do when using local
>> transactions (even with a single producer/consumer), since the commit method
>> is on the session. Perhaps we should add a new commit method on the
>> producer/consumer as a convenience? (Just like we have an acknowledge method
>> on Message as a convenience, even though it operates on the whole session).
>>
>
> Agreed. Should we start a separate proposal for this?
>
>
>>
>>
>>
>>>
>>> 9. Injecting a Message
>>> ----------------------
>>>
>>
>> This idea of a MessageFactory is a good idea, one I had been contemplating
>> for the main API and which we should consider in this wider context.
>>
>>
>>> You suggest a new MessageFactory class which can be used to instantiate
>>> provider-specific message impementations:
>>>
>>> //Instantiate the default MessageFactory implementation.
>>> MessageFactory messageFactory = new MessageFactory();
>>> TextMessage textMessage =
>>> messageFactory.createMessage(TextMessage.class);
>>>
>>> You suggest that the "JMS Implementation that is in use" would define the
>>> actual MessageFactory implementation class in the resource directory
>>> META-INF/services.
>>>
>>> I support the idea of separating from the Session object the factory
>>> methods to create messages, but I'm not sure whether the ServiceLoader
>>> mechanism is going to work, for a number of reasons:
>>>
>>> a. The ServiceLoader mechanism doesn't seem to allow multiple
>>> MessageFactory implementations to be used within the same application. This
>>> would cause problems from applications that needed to use two different JMS
>>> providers at the same time.
>>>
>>
>> I thought about this. I would recommend using a qualifier to control this
>> at the injection level. For example: @Inject @JmsProvider(“WebLogic”)
>> MessageFactory messageFactory.
>>
>>
>> I don't think we would want that as it would defeat the JMS goal of
>> keeping vendor-specific configuration out of the code.
>>
>> But even then I'm not sure it'll be required. Would we perhaps expect
>> the opposite, that MessageFactory would take the underlying implementation's
>> interfaces as arguments intead?
>>
>> There isn't currently any concept of "underlying implementation" -
>> especially in Java SE. As you mentioned yourself, an application might be
>> using two JMS providers.
>>
>>
>>
>>
>>>
>>> b. The idea of using a classpath resource to define what JMS provider is
>>> being used is inconsistent with the existing convention of using a JNDI
>>> resource.
>>>
>>
>> I probably misstated something. Classpath would be used to state what
>> Messages were available for use, based on how ServiceLoaders work.
>>
>>
>>
>> The ServiceLoader mechanism is being used to define a provider-specific
>> MessageFactory. This means that users would be using the classpath to define
>> what provider they were using to create messages. Whereas currently users
>> define what provider they are using to create connections by using JNDI. I
>> was observing that this was inconsistent.
>>
>>
>>
>>> c. In a Java EE application it would seem to prevent two separate JMS
>>> providers being made available in the same global classpath, for use by
>>> different applications.
>>>
>>
>> I'm not sure why this is implied. Could you explain further?
>>
>>
>> If both applications (running in the same application server) had the
>> same classpath then they would be forced to use the same MessageFactory.
>>
>>
>>
>>
>>>
>>> I've been trying to think of an alternative, none of which seem very
>>> attractive: the best I can think up is
>>>
>>> x. Simply clarify in the spec that messages created using the existing
>>> API are not associated with the Session used to create them,
>>>
>>
>> This is the really just the current situation. The application would have
>> to find a Session (any Session from the required provider) and use it to
>> create Messages.
>>
>> I was wondering whether we could invent a different MessageFactory class
>> which held a reference to a Session, and used that Session to create
>> objects. Applications could then inject MessageFactorys in the same way as
>> they can inject MessageProducers. But with dependent scope, I think this
>> would mean that we'd create a new connection and a new session just so we
>> could create messages, which is clearly unacceptable.
>>
>>
>>> y. Move the factory methods to ConnectionFactory
>>>
>>
>> I mean a new createMessage() method on javax.jms.ConnectionFactory. Since
>> the ConnectionFactory is provider-specific it would know how to instantiate
>> messages.
>>
>> Again we could invent a different MessageFactory class which held a
>> reference to a ConnectionFactory, and inject that. This would mean a JNDI
>> lookup whenever we wanted to create inject a MessageFactory, but that isn't
>> so bad.
>>
>>
>>
>>> z. Require MessageFactory objects to be looked up from JNDI
>>>
>>
>> Could you explain this a bit further?
>>
>>
>> Given that your propoed MessageFactory is a provider-specific object, we
>> should ask administrators to instantiate one, using provider-specific tools,
>> and bind it to JNDI for the application to lookup. This would be entirely
>> analogous with the way in which connection factories and destinations are
>> created, bound, and looked up now.
>>
>>
> Actually, I was hoping that it wouldn't be provider specific. I noted in
> my response to Reza that it should end up in the connection factory, for
> session nonspecific messaging..
>
>
>> Nigel
>>
>>
>>
>>
>>>
>>> 10. Miscellaneous
>>> -----------------
>>>
>>> A. In the example on page 7:
>>>
>>> @Inject
>>> @JmsConnection(factory=”/JmsXA”,transacted=true)
>>> @JmsDestination(“jms/SomeStaticDestination”)
>>> MessageProducer staticProducer;
>>>
>>> Can you clarify why you think of these as "static"?
>>>
>>
>> I'll restate the example as:
>>
>> @Inject
>> @JmsConnection(factory=”/JmsXA”,transacted=true)
>> @JmsDestination(“jms/SomeFooDestination”)
>> MessageProducer fooProducer;
>>
>>>
>>> B. In the example on pages 7-8:
>>>
>>> @ApplicationScoped
>>> public class HandleMessages {
>>>
>>> @Inject
>>> @JmsConnection(factory=”/JmsXA”,transacted=true)
>>> @JmsDestination(“jms/SomeStaticDestination”)
>>> MessageConsumer genericConsumer;
>>>
>>> //handles a generic application driven event to look for messages and
>>> process them.
>>> //MyApplicationEvent is an event raised by the application and defined
>>> by the application itself.
>>> public void lookForMessages(@Observes MyApplicationEvent evt) {
>>> TextMessage received = null;
>>> while((received = genericConsumer.receive(3000l,TextMessage.class))
>>> != null) {
>>> String text = received.getText();
>>> doWork(text);
>>> }
>>> }
>>>
>>> Is there any particular reason why you used events here? I think it might
>>> be better to choose an example which doesn't use CDI events since it might
>>> give the midleading impression that we're defining an event API here.
>>>
>>
>> I thought about that after I sent it out, and will probably change the
>> example to use an EJB timer. I was trying to setup something really simple
>> to use as an example.
>>
>>
>>>
>>>
>>>
>>>
>>>
>>> Nigel
>>>
>>>
>>>
>>>
>>>
>>
> ------------------------------
>
> No virus found in this message.
> Checked by AVG - www.avg.com
> Version: 10.0.1392 / Virus Database: 1520/3867 - Release Date: 08/30/11
>
>
>