You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@openwebbeans.apache.org by David Blevins <da...@visi.com> on 2009/10/15 11:18:20 UTC

Interceptors and Decorators

As Mark is hammering on the observer code (thanks, Mark!), I moved  
over to Interceptors and am mulling over that code.  For those that  
like to follow along, most the code is in InterceptorHandler.  Ran  
into some related Decorator stuff as well.

INTERCEPTOR RELATED

First a small note, in the current code there is one interceptor stack  
per component, rather than per method.  I see how we copy the list on  
each invoke and filter out the interceptors that do not apply to the  
method being invoked, but I didn't see if we were maintaining order in  
that list.  Figured I'd just ask where the original list was created  
so I could take a look -- faster than digging.  Pointer is welcome.

A side note on the above, I think we could use some more diversity in  
the related tests.  So far we don't have any components that have more  
than one interceptable method, so most the above logic is  
unchallenged.  We should definitely add some tests that verify you  
only get interceptors that were declared in your method and not ones  
from other methods as well as verifying the order is as declared on  
the method.  The current code shouldn't have a problem with that, but  
if someone wanted something to do, that'd be a great contribution.

One area not implemented is something barely mentioned in the  
interceptor spec, but I know is tested in the EJB spec at least, is  
the concept of "Disable via override."  If an @AroundInvoke method is  
overridden in a subclass without also being annotated @AroundInvoke,  
then this must dissable the around invoke method and it should not be  
called.  This applies to @AroundInvoke methods in beans and  
interceptors.  It also applies to @PostConstruct and @PreDestroy  
callbacks.

INTERCEPTORS and DECORATORS

It looks as though the part of the spec that says "Decorators are  
called after interceptors" was taken differently than intended.   
Currently, the interceptor stack wraps the target bean and the  
decorator "stack" more or less just gets a notification of the  
invocation as a separate after thought.  As well Decorators were  
implemented as a list that is iterated over, rather than as a stack  
where one decorator calls the next in the chain.

Interceptors and Decorators are completely identical and part of the  
same overall invocation stack.  They both wrap an object and delegate  
to it.  They both can manipulate the method parameters and both can  
manipulate the return value (or exception).  The only difference is  
Interceptors are very reflection-like and Decorators are strongly typed.

So what "Decorators are called after interceptors" means is that one  
stack is created and in that stack interceptors are invoked first,  
decorators are invoked second, and the target bean method is invoked  
last.  The wording is unfortunate as it also means that the opposite  
is true on the way out: the bean returns and that value propagates  
back up the stack to the decorators, then the interceptors.  So  
Interceptors and Decorators all wrap each other like one big onion.   
Interceptors are the outer most layers of the onion, the decorator  
layers follow, and finally the bean itself is the center.

 From an implementation standpoint what it means is that the last  
interceptor in the interceptor part of the stack is actually going to  
invoke the first decorator in that part of the stack and the  
invocation will continue.  Code wise there's no real way for that last  
interceptor to know if its invoking the bean or a decorator that  
implements the same interface and method as the bean.  It just calls  
what it was given.  So we just need to make an actual stack out of the  
decorators and pass that into the interceptor stack in place of where  
we pass the bean now.

If someone has time that's another good area for contribution.


-David



Re: Interceptors and Decorators

Posted by David Blevins <da...@visi.com>.
Great info!  Some form of all this could make for great javadoc at the  
top of the InterceptorHandler class.  At minimum a few "@see" pointers  
to the code mentioned.


On Oct 15, 2009, at 5:45 AM, Gurkan Erdogdu wrote:

> Currently interceptors and decorators are supported for  the "Managed
> Beans".  OWB delegates calling of "EJB Beans" interceptors to the EJB
> container.  It does not provide built-in interceptor and decorator  
> support
> for EJB beans.

This would be great code for the OpenWebBeansEjbInterceptor.   
Essentially it would have an @AroundInvoke method and be placed last  
in the EJB interceptor stack.  In its @AroundInvoke method it would  
call the "web beans" Interceptors, call all the Decorators, and then  
finally call invocationContext.proceed() which effectively hands  
control back to the ejb container who then invokes the EJB bean  
instance's target method. I left out a lot of tricky details, but  
that's how it could work at a high level.

> Current implementation supports configuration of the
> interceptors on the "Managed Beans" with 2 different scenarios,  
> i.e.  it
> supports "EJB related interceptors ( defined by EJB specification)"  
> and
> "JSR-299 related interceptors (defined by interceptor bindings)".

Spec note that @InterceptorBinding is moving into the  
javax.interceptor package and will be part of the EJB Interceptor  
spec.  The actual definition of it now will still remain in 299 and  
EJB 3.1 containers won't be required to support it, but in the future  
they likely will.

So in the future the line between "EJB" Interceptor and "WebBeans"  
interceptor will get pretty blurry -- more so than it already is.   
There'll be pretty much no line :)  Hopefully Decorators will be added  
to EJB.next as well (I wanted them in EJB 3.1, but there just wasn't  
enough bandwidth to address it), in which case the overlap between EJB  
and WebBeans will get even bigger.  Might be an opportunity for code  
reuse between OpenEJB and OpenWebBeans down the line.

> "EJBInterceptorConfig" class is responsible for finding all  
> interceptors for
> given managed bean class according to the EJB Specification. (But as  
> you
> said, it may not include @AroundInvoke/@PostConstruct etc. disablement
> scenario!).

No worries there, it's an obscure requirement even we (OpenEJB) didn't  
find till we started running the TCK.  We (OWB) can add it easily  
later without much change to the way the code is written.

> 3* Invocation of Interceptors and Decorators
>
> Invocation is handled by the "InterceptorHandler" class [...] After  
> that it filters
> interceptor stack for calling method (Current design of filtering  
> may not be
> optimal!).

I gave that chunk of code a good long mental scrubbing and even  
started to write some notes on changing it, but I like it more and  
more.  Checking equals on a small number of objects is pretty quick,  
usually faster than an array copy.  There usually aren't a large  
number of interceptors and if there are they are typically defined at  
the class level or more generallly -- at the method level is less  
common.  Any scenario involving starting with an empty array  
(ArrayList) and adding items to it could involve growing that  
ArrayList.  If we start with the full list, copy it, then yank out the  
values that don't apply, we guarantee that the first array created is  
the right size.  So the logic involves no hash lookups and exactly one  
array copy.  The filtering is mostly boolean comparisons until we  
reach the entries that apply to specific methods and start  
calling .equals().

The only other way for it to be faster is to go the exact opposite  
approach and build a full stack for each method in advance, so the  
entire stack is one hashmap lookup away and the method is the key.   
Building one stack per method can be bad.  I've found that doing that  
kind of processing in advance can significantly raise the deployment  
cost.  Doing special processing for every method can really drag  
startup as the number of beans and methods increase.  This way,  
there's no actual growing cost when beans/methods increase, just when  
the number of interceptors increase and that's almost always going to  
be a smaller number.

I'm very tempted to go back and rewrite the related OpenEJB code.

A small note is that InterceptorHandler actually doesn't do the list  
copy in they way I describe -- it copies one item at a time which  
could grow the original array in the new ArrayList -- but that's a one  
line change.  Can just pass the read-only array into the ArrayList  
constructor when creating the temp list.  Then what I mention is true.

Good small focused change if someone wants to throw that in real quick.

> The correct way may be that after executing last interceptor  
> instance, it
> looks for the decorator stack. If decorator stack is not empty, it  
> exhausts
> all decorators before calling actual method. (I1 --> I2 --> D1 -->  
> Actual
> Method). This issue can be resolved easily by updating  
> *InterceptorHandle*
> code.

Right, exactly.

-David


Re: Interceptors and Decorators

Posted by Gurkan Erdogdu <cg...@gmail.com>.
Hi David;

Thanks a lot for great comment!

Firstly, I would like to explain how decorators and interceptors of  beans
are constructed and invoked by the current implementation. According to the
spec. "Decorator" and "WebBeans Interceptors" are just another beans.  In
the early versions of the spec. contains a "fully functional interceptor"
chapter but now it is superseded by the "Interceptor Binding" section. I
wrote  most of the interceptor logic code according to the early spec.
requirements, but it looks that it is still valid.

I will try to explain how I implemented decorator and interceptor related
functionality in detailed below. So any tinker can work on an old code :)

Let's dive into the code;

1- Configuration of  decorators and interceptors
    Decorators and Interceptors are configured from
"WebBeansContainerDeployer" class via methods
"configureInterceptors(scanner)" and "configureDecorators(scanner)". Those
methods further call "defineInterceptor(interceptor class)" and
"defineDecorator(decorator class)" methods. Those methods finally call
"WebBeansUtil#defineInterceptors" and "WebBeansUtil#defineDecorators"
methods for actual configuration.

Let's look at the "WebBeansUtil's" methods;

*defineInterceptors* : This method firstly creates a "Managed Bean" for the
given interceptor with "WebBeansType.INTERCEPTOR" as a type. After checking
some controls, it calls
"WebBeansInterceptorConfig#configureInterceptorClass".
"configureInterceptorClass" method creates a "WebBeansInterceptor" instance
that wraps the given managed bean instance and configuring interceptor's
*Interceptor Binding* annotations. If everything goes well, it adds
interceptor instance into the "BeanManager" interceptor list.

*defineDecorators* : Exactly doing same thing as "defineInterceptors". If
everything goes well, it adds decorator instance into the "BeanManager"
decorator list.

2* Configuring ManagedBean Instance Interceptor and Decorator Stack

Currently interceptors and decorators are supported for  the "Managed
Beans".  OWB delegates calling of "EJB Beans" interceptors to the EJB
container.  It does not provide built-in interceptor and decorator support
for EJB beans. Current implementation supports configuration of the
interceptors on the "Managed Beans" with 2 different scenarios, i.e.  it
supports "EJB related interceptors ( defined by EJB specification)" and
"JSR-299 related interceptors (defined by interceptor bindings)".

Lets look at the code for configuring "Managed Beans" interceptor and
decorator stack.

Managed Beans interceptor and decorator stacks are configured after they are
instantiated by the container first time. This method can be found in the
"AbstractInjectionTargetBean" class "afterConstructor()" method. Actual
configuration is done by the
"DefinitionUtil.defineSimpleWebBeanInterceptorStack" and
"DefinitionUtil.defineSimpleWebBeanDecoratorStack".

 public static void
defineSimpleWebBeanInterceptorStack(AbstractBean<?> component)
>     {
>         Asserts.assertNotNull(component, "component parameter can no be null");
>
>         // @javax.interceptor.Interceptors
>         EJBInterceptorConfig.configure(component.getReturnType(), component.getInterceptorStack());
>
>         // @javax.webbeans.Interceptor
>         WebBeansInterceptorConfig.configure(component, component.getInterceptorStack());
>     }
>
>     public static void defineWebBeanDecoratorStack(AbstractBean<?> component, Object object)
>     {
>         WebBeansDecoratorConfig.configureDecarotors(component, object);
>     }
>
>
In "DefinitionUtil.defineSimpleWebBeanInterceptorStack", firstly it
configures "EJB spec. interceptors" after that configures "JSR-299 spec.
interceptors."
In "DefinitionUtil.defineSimpleWebBeanDecoratorStack", it configures
decorator stack.

"EJBInterceptorConfig" class is responsible for finding all interceptors for
given managed bean class according to the EJB Specification. (But as you
said, it may not include @AroundInvoke/@PostConstruct etc. disablement
scenario!). "WebBeansInterceptorConfig" class is responsible for finding all
interceptors for a given managed bean class according to the "JSR-299,
spec." It adds all interceptors into the bean's interceptor stack. It first
adds "EJB" related interceptors, after that adds "JSR-299" related
interceptors. For "JSR-299" related interceptors, it orders the interceptors
according to the "InterceptorComparator". Basically, it puts interceptors in
order according to how they are ordered in a "beans.xml" configuration file.

Similarly, it configures managed bean's decorator stack according to the
decorator resolution rules. Also, it orders decorators according to the
"beans.xml" configuration file that contains decorator declarations.

3* Invocation of Interceptors and Decorators

Invocation is handled by the "InterceptorHandler" class (It has an absurd
name, it can be changed to a more meaningful name :)). It works nearly same
as  what you have explained. First of all, it checks that calling method is
a business method of a managed bean or not. After that it filters
interceptor stack for calling method (Current design of filtering may not be
optimal!). Firstly it adds EJB interceptor to the list and then adds JSR-299
interceptors. After that, it starts to call all interceptors in order. After
consuming all interceptors it calls decorators. (as you explained, seems
that the logic may not be correct here. Currently, interceptors and
decorators are not related with each other. They are called independently).

Lets say that 2 interceptor and 1 decorator instance on the stack. Currently
it calls interceptor's @AroundInvoke methods, calls actual method of bean
instance and calls decorator stack and return the interceptor execution
result. This seems incorrect.

The correct way may be that after executing last interceptor instance, it
looks for the decorator stack. If decorator stack is not empty, it exhausts
all decorators before calling actual method. (I1 --> I2 --> D1 --> Actual
Method). This issue can be resolved easily by updating *InterceptorHandle*
code.

I hope that it helps!

Thanks;

--Gurkan


2009/10/15 David Blevins <da...@visi.com>

> As Mark is hammering on the observer code (thanks, Mark!), I moved over to
> Interceptors and am mulling over that code.  For those that like to follow
> along, most the code is in InterceptorHandler.  Ran into some related
> Decorator stuff as well.
>
> INTERCEPTOR RELATED
>
> First a small note, in the current code there is one interceptor stack per
> component, rather than per method.  I see how we copy the list on each
> invoke and filter out the interceptors that do not apply to the method being
> invoked, but I didn't see if we were maintaining order in that list.
>  Figured I'd just ask where the original list was created so I could take a
> look -- faster than digging.  Pointer is welcome.
>
> A side note on the above, I think we could use some more diversity in the
> related tests.  So far we don't have any components that have more than one
> interceptable method, so most the above logic is unchallenged.  We should
> definitely add some tests that verify you only get interceptors that were
> declared in your method and not ones from other methods as well as verifying
> the order is as declared on the method.  The current code shouldn't have a
> problem with that, but if someone wanted something to do, that'd be a great
> contribution.
>
> One area not implemented is something barely mentioned in the interceptor
> spec, but I know is tested in the EJB spec at least, is the concept of
> "Disable via override."  If an @AroundInvoke method is overridden in a
> subclass without also being annotated @AroundInvoke, then this must dissable
> the around invoke method and it should not be called.  This applies to
> @AroundInvoke methods in beans and interceptors.  It also applies to
> @PostConstruct and @PreDestroy callbacks.
>
> INTERCEPTORS and DECORATORS
>
> It looks as though the part of the spec that says "Decorators are called
> after interceptors" was taken differently than intended.  Currently, the
> interceptor stack wraps the target bean and the decorator "stack" more or
> less just gets a notification of the invocation as a separate after thought.
>  As well Decorators were implemented as a list that is iterated over, rather
> than as a stack where one decorator calls the next in the chain.
>
> Interceptors and Decorators are completely identical and part of the same
> overall invocation stack.  They both wrap an object and delegate to it.
>  They both can manipulate the method parameters and both can manipulate the
> return value (or exception).  The only difference is Interceptors are very
> reflection-like and Decorators are strongly typed.
>
> So what "Decorators are called after interceptors" means is that one stack
> is created and in that stack interceptors are invoked first, decorators are
> invoked second, and the target bean method is invoked last.  The wording is
> unfortunate as it also means that the opposite is true on the way out: the
> bean returns and that value propagates back up the stack to the decorators,
> then the interceptors.  So Interceptors and Decorators all wrap each other
> like one big onion.  Interceptors are the outer most layers of the onion,
> the decorator layers follow, and finally the bean itself is the center.
>
> From an implementation standpoint what it means is that the last
> interceptor in the interceptor part of the stack is actually going to invoke
> the first decorator in that part of the stack and the invocation will
> continue.  Code wise there's no real way for that last interceptor to know
> if its invoking the bean or a decorator that implements the same interface
> and method as the bean.  It just calls what it was given.  So we just need
> to make an actual stack out of the decorators and pass that into the
> interceptor stack in place of where we pass the bean now.
>
> If someone has time that's another good area for contribution.
>
>
> -David
>
>
>


-- 
Gurkan Erdogdu
http://gurkanerdogdu.blogspot.com

Re: Interceptors and Decorators

Posted by Mark Struberg <st...@yahoo.de>.
If it helps, I think I enabled cobertura for the site plugin.

I will do a site deploy-staged to my people@ao in the afternoon. 
The public site needs to be updated too I think.

LieGrue,
strub



----- Original Message ----
> From: David Blevins <da...@visi.com>
> To: openwebbeans-dev@incubator.apache.org
> Sent: Thu, October 15, 2009 11:18:20 AM
> Subject: Interceptors and Decorators
> 
> As Mark is hammering on the observer code (thanks, Mark!), I moved over to 
> Interceptors and am mulling over that code.  For those that like to follow 
> along, most the code is in InterceptorHandler.  Ran into some related Decorator 
> stuff as well.
> 
> INTERCEPTOR RELATED
> 
> First a small note, in the current code there is one interceptor stack per 
> component, rather than per method.  I see how we copy the list on each invoke 
> and filter out the interceptors that do not apply to the method being invoked, 
> but I didn't see if we were maintaining order in that list.  Figured I'd just 
> ask where the original list was created so I could take a look -- faster than 
> digging.  Pointer is welcome.
> 
> A side note on the above, I think we could use some more diversity in the 
> related tests.  So far we don't have any components that have more than one 
> interceptable method, so most the above logic is unchallenged.  We should 
> definitely add some tests that verify you only get interceptors that were 
> declared in your method and not ones from other methods as well as verifying the 
> order is as declared on the method.  The current code shouldn't have a problem 
> with that, but if someone wanted something to do, that'd be a great 
> contribution.
> 
> One area not implemented is something barely mentioned in the interceptor spec, 
> but I know is tested in the EJB spec at least, is the concept of "Disable via 
> override."  If an @AroundInvoke method is overridden in a subclass without also 
> being annotated @AroundInvoke, then this must dissable the around invoke method 
> and it should not be called.  This applies to @AroundInvoke methods in beans and 
> interceptors.  It also applies to @PostConstruct and @PreDestroy callbacks.
> 
> INTERCEPTORS and DECORATORS
> 
> It looks as though the part of the spec that says "Decorators are called after 
> interceptors" was taken differently than intended.  Currently, the interceptor 
> stack wraps the target bean and the decorator "stack" more or less just gets a 
> notification of the invocation as a separate after thought.  As well Decorators 
> were implemented as a list that is iterated over, rather than as a stack where 
> one decorator calls the next in the chain.
> 
> Interceptors and Decorators are completely identical and part of the same 
> overall invocation stack.  They both wrap an object and delegate to it.  They 
> both can manipulate the method parameters and both can manipulate the return 
> value (or exception).  The only difference is Interceptors are very 
> reflection-like and Decorators are strongly typed.
> 
> So what "Decorators are called after interceptors" means is that one stack is 
> created and in that stack interceptors are invoked first, decorators are invoked 
> second, and the target bean method is invoked last.  The wording is unfortunate 
> as it also means that the opposite is true on the way out: the bean returns and 
> that value propagates back up the stack to the decorators, then the 
> interceptors.  So Interceptors and Decorators all wrap each other like one big 
> onion.  Interceptors are the outer most layers of the onion, the decorator 
> layers follow, and finally the bean itself is the center.
> 
> From an implementation standpoint what it means is that the last interceptor in 
> the interceptor part of the stack is actually going to invoke the first 
> decorator in that part of the stack and the invocation will continue.  Code wise 
> there's no real way for that last interceptor to know if its invoking the bean 
> or a decorator that implements the same interface and method as the bean.  It 
> just calls what it was given.  So we just need to make an actual stack out of 
> the decorators and pass that into the interceptor stack in place of where we 
> pass the bean now.
> 
> If someone has time that's another good area for contribution.
> 
> 
> -David