[webbeans-dev] Re: @Supports

Scott Ferguson ferg at caucho.com
Sat Nov 15 12:46:42 EST 2008


On Nov 14, 2008, at 11:58 AM, Gavin King 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.

Sounds good.  The <Topic> and <Queue> special cases are strange.   I  
think, though, that the current JMS could be simplified tremendously  
by using a special pseudo-scope on the QueueEndpoint.

Because the QueueEndpoint is a collection of related objects with a  
common lifecycle, it makes sense to model it as a simple bean with the  
proper scope and the @Produces as accessors to the objects. The scope  
of the QueueEndpoint is dependent on the bean it's is injecting into.   
When multiple @Produces are used by the target bean, the same  
QueueEndpoint is used as a factory object.

So an injection of MyBean:

public class MyBean {
   @PaymentProcessor QueueSender _paymentSender;
   @PaymentProcessor QueueSession _paymentSession;
}

Would look like:

   1. endpoint = new QueueEndpoint(); // triggered by first injection
   2. endpoint.init();
   3. endpoint.createQueueSender(); // first injection
   4. endpoint.createQueueSession(); // endpoint grabbed from pseudo- 
scope for 2nd injection
   ...
   5. endpoint.destroy();

I don't see any need for a proxy at all in this case.  Unless there's  
something I'm missing, the only issue is the scope of the factory  
object.

@DependentFactoryScoped
public class QueueEndpoint {
   private Queue _queue;
   private QueueConnection _conn;
   private QueueSession _queueSession;
   ....

   @PostConstruct
   public void init()
   {
      // do any JNDI lookup, session creation, etc.  (or do lazily)
   }

   @Produces
   public Queue createQueue() { return _queue; }
   @Produces
   public QueueSession createQueueSession() { return _queueSession; }

   ...

   @PreDestroy
   public void destroy()
   {
     // shutdown
   }
}

-- Scott

> 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#d0e4283
>
> (@Factory is more or less like @Produces, whereas @Unwrap is a really
> crappy version of @Supports.)
>
> -- 
> Gavin King
> gavin.king at gmail.com
> http://in.relation.to/Bloggers/Gavin
> http://hibernate.org
> http://seamframework.org
>
>




More information about the weld-dev mailing list