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