An alternative solution to this problem would be to define the notion
of a "prototype" producer:
@ApplicationScoped
public class QueueEndpoint {
...
@Prototype @Produces Queue getQueue() { ... }
@Prototype @Produces getQueueSession() { ... }
@Prototype @Produces getQueueSender() { ... }
@Prototype @Produces getQueueConnection() { ... }
}
The effect of the @Prototype annotation would be to define a producer
method for every Web Bean which has the implementation class
QueueEndpoint or a subclass. (Without the @Prototype annotation, there
is exactly one producer method declared.) Each of these producer
methods would have the same deployment type and binding types as the
Web Bean with which they are associated.
For example, If I configure a Queue in XML:
<Queue>
<destination>java:/comp/env/jms/PriceQueue</destination>
<connectionFactory>...</connectionFactory>
<myapp:Prices/>
</Queue>
Then I get four producer methods with binding type @Prices.
If I add the following subclass:
@Staging @Special
public class MySpecialQueueEndpoint extends QueueEndpoint {
...
}
Then there would be four new producer methods, each with deployment
type @Staging and binding type @Special.
The advantages of the approach are:
* it avoids introducing a whole new first-level construct
* it can also be applied to other "non-inherited" constructs (disposal
and observer methods)
* it avoids the problem of ambiguous method names
* types other than interfaces are supported
* the object returned by the producer method can have any scope
On the downside:
* I think it's slightly more difficult to explain
* you can't typecast the client proxy between the various types
* you don't inherit the interceptors of the "owning" Web Bean (good or
bad?)
* it's a bit less dynamic - the producer method is not called for
every method invocation
* potential problems when subtypes change the scope of the "owning" Web Bean
On Fri, Nov 14, 2008 at 2:58 PM, Gavin King <gavin(a)hibernate.org> wrote:
I've been thinking about the problem of implementing re-usable
components like our JMS endpoints. What I'm trying to do is implement
the requirements of JMS endpoints as a simple Web Bean. To do that
today, I would need to create a class which implemented all the API
types:
@ApplicationScoped
public class QueueEndpoint
implements Queue, QueueSession, QueueSender, QueueConnection { ... }
and I would have to go and implement every one of the operations of
each of those interfaces to delegate to the correct object. (A bunch
of tedious code.)
However, if we assume that the client proxy is smart enough, we could
let the Web Bean manager automagically do that delegation for us. We
would need a new annotation that could be applied to fields or
methods, for example:
@ApplicationScoped
public class QueueEndpoint {
...
@Supports Queue getQueue() { ... }
@Supports QueueSession getQueueSession() { ... }
@Supports QueueSender getQueueSender() { ... }
@Supports QueueConnection getQueueConnection() { ... }
}
We no longer need to write all those annoying delegation methods! The
client proxy would just call the correct @Supports method when the
QueueEndpoint type did not define the method that was invoked by the
client, and delegate the method to the returned object.
To make this really work, we would need to say:
* the set of API types of the Web Bean includes all types of @Supports
methods/fields
* if a certain method name appears on more than one @Supports
method/field type, it must also be implemented directly by the impl
class
* if a certain method name appears on more than one @Supports
method/field type, or on both the impl class and a @Supports
method/field type, it is always called on the impl class
Therefore, close() would need to be implemented by QueueEndpoint:
@ApplicationScoped
public class QueueEndpoint {
...
@Supports Queue getQueue() { ... }
@Supports QueueSession getQueueSession() { ... }
@Supports QueueSender getQueueSender() { ... }
@Supports QueueConnection getQueueConnection() { ... }
void close() { throw new UnsupportedOperationException(); }
}
You're probably thinking that we can do all this with @Producer
methods, however, the semantics are not exactly the same, since the
association b/w the producer object and produced object is lost as
soon as the producer method returns. Furthermore, @Producer methods
aren't really appropriate for 3rd-party reusable objects, since the
XML configuration of a producer method is verbose.
I don't believe that Web Beans 1.0 absolutely has to have this
feature, but I know its useful, and I know that we will implement it
in the RI, so I would prefer if it was portable. What do you guys
think? Useful? Too much magic? Let me know...
Seam already has an extremely primitive/braindead version of this
feature, that I've found *extremely* useful when writing reusable
components:
http://docs.jboss.com/seam/2.1.0.SP1/reference/en-US/html/concepts.html#d...
(@Factory is more or less like @Produces, whereas @Unwrap is a really
crappy version of @Supports.)
--
Gavin King
gavin.king(a)gmail.com
http://in.relation.to/Bloggers/Gavin
http://hibernate.org
http://seamframework.org