jsr343-experts@jms-spec.java.net

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

From: Reza Rahman <reza_rahman_at_lycos.com>
Date: Tue, 30 Aug 2011 22:54:53 -0400

John,

I'm not sure that we are actually disagreeing :-). I'm not actually
suggesting that this feature be enabled by default or that CDI should
not be used in a Java EE environment (although it could be if we make
certain decisions that I do not necessarily agree with). Clarification
below:

I don't think this is an adapter situation at all, but just an
abstraction over plain JMS in a Java EE environment (that happens to
include CDI). The fact that the abstraction is implemented using CDI is
actually a fairly minor implementation detail. As a thought experiment,
imagine how this might be implemented without using @Inject altogether
and simply using @Resource or a similar annotation such as just
@JmsSession, @JmsConnection, etc (along the lines of Nigel's suggestion
and more in line with @PersistenceContext; this could even include
transaction scoping of JMS objects just as JPA does for the JPA
transaction scoped persistence context).

That being said, yet again, we can state that in a Java EE environment,
injection is to be done using CDI (in this case, the only real
significance from the standardization standpoint is requiring the
existence of META-INF/beans.xml in the archive for this functionality to
be enabled). The point is really that I think the proposal could be
written using just JSR 330 annotations and no CDI API is actually
necessary, still keeping the door open for others to create this
functionality as well, albeit in a way that is not 100% TCK compatible
(much like how Spring supports JSR 330, JSR 250, JPA, etc similar to how
a Java EE application server does).

Hope this makes sense. It might be easier to discuss this "in person".

Cheers,
Reza


On 8/30/2011 8:13 PM, John D. Ament wrote:
> Reza,
>
> On Tue, Aug 30, 2011 at 8:01 PM, Reza Rahman <reza_rahman_at_lycos.com
> <mailto: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 <mailto: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 <mailto: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 <http://www.avg.com>
>> Version: 10.0.1392 / Virus Database: 1520/3867 - Release Date:
>> 08/30/11
>>
>
>
> ------------------------------------------------------------------------
>
> No virus found in this message.
> Checked by AVG - www.avg.com <http://www.avg.com>
> Version: 10.0.1392 / Virus Database: 1520/3868 - Release Date: 08/30/11
>