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