|
From: roger h. <apo...@sn...> - 2003-11-08 19:06:48
|
Rod
If IntroductionAdvice getInterfaces() method is to return the same as the
IntroductionInterceptor getIntroducedInterfaces() does at present, then
whichever interface this method ends up on, I would like to suggest a
variation on this scheme...
The key thing about these interfaces returned by getIntroducedInterfaces(),
is that they are actually the set of interfaces that are 'implemented' by
the introduction interceptor. As such I don't think they should be showing
up in an IntroductionAdvice, which is effectively providing a conditional
'declaration' for an extended proxy class.
In the current implementation, there is no distinction between Declared
interfaces and Implemented interfaces. If such a distinction is introduced,
I think it could offer opportunities for enhancing the ways in which Proxy's
can be composed.
Specifically, an introduction could distinguish between a single 'declared
interface' for which it contracts to provide an implementation, and the set
of 'implemented interfaces' that it actually delivers in the process.
In other words, an IntroductionInterceptor could effectively define methods:
Class getDeclaredInterface()
Class[] getImplementedInterfaces()
and a ProxyConfig, could provide a corresponding distinction:
Class[] getDeclaredInterfaces()
Class[] getImplementedInterfaces()
where the 'declared interfaces' are the ones that are actually implemented
directly by the target class.
Once an introduction can be tied to a single declared interface, it then
becomes possible to setup an IntroductionFactoryBean that can satisfy that
individual interface. Indeed, the name of the interface can also then be
used to identify and reference an instance of introduction factory bean.
Now the xml bean config file can be used to bind these
IntroductionFactoryBean implementations both to Interceptor names & to
Interface names.
Then, it becomes possible to provide ProxyFactoryBean definitions looking
like:
<!-- Simple target -->
<bean id="employee" class="org.springframework.beans.Employee">
<property name="name"><value>name of employee</value></property>
</bean>
<!-- Simple Introduction -->
<bean id="testIntro1" class="org.springframework.beans.TestBean">
<property name="name"><value>name of testIntro1</value></property>
</bean>
<!-- IntroductionFactoryBean -->
<bean id="testIFB1"
class="org.springframework.aop.framework.IntroductionFactoryBean">
<property name="interfaceName">
<value>org.springframework.beans.ITestBean</value></property>
<property name="interceptorNames"><value>testIntro1</value></property>
<property name="singleton"><value>false</value></property>
</bean>
<!-- Convenient 'Interface' Name for this IntroductionFactoryBean -->
<bean id="org.springframework.beans.ITestBean"
parent="testIFB1">
</bean>
<!-- ProxyFactoryBean using the named Interceptor /
IntroductionFactoryBean -->
<bean id="testPFB1"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interceptorNames">
<value>testIFB1,employee</value></property>
</bean>
<!-- ProxyFactoryBean using the named Interface /
IntroductionFactoryBean -->
<bean id="testPFB2"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value>org.springframework.beans.ITestBean</value></property>
<property name="interceptorNames"><value>employee</value></property>
</bean>
Note the significant thing about the above example is that the 2
ProxyFactoryBeans will produce identical proxy instances, and they will
actually use the same IntroductionFactoryBean - but one is matching the
reference to a proxy Interface, while the other is matching a reference to
an Interceptor.
From a programmatic point of view, the link between Declared Interfaces and
IntroductionFactoryBeans, can also be exploited to dynamically re-implement
a Proxy instance - ie. using code that looks something like:
public class DynamicProxyFactory implements BeanFactoryAware {
// given an existing proxy instance, construct and return a new one
// that retains the old target and introduction instances, and adds
// new introductions for the requested interface.
Object addInterface(Object proxy, Class intf)
// given an existing proxy instance, construct and return a new one
// that retains the old target and those introduction instances other than
// the one that is to be removed. If the removed interface is actually
// declared on the target, then it can be masked by suppressing
// corresponding set of implemented interfaces
Object removeInterface(Object proxy, Class intf)
// as above for but for all the requested additional interfaces
Object addAllInterfaces(Object proxy, Class[] interfaces)
// as above for but for all the requested removed interfaces
Object removeAllInterfaces(Object proxy, Class[] interfaces)
// given an existing proxy instance, construct and return a new one
// that retains the old target instance and those introduction instances
// that provide the requested interfaces. If any of the interfaces not to
// retained is actually declared on the target, then it will be masked by
// suppressing corresponding set of implemented interfaces
Object retainAllInterfaces(Object proxy, Class[] interfaces)
// given an existing proxy instance, construct and return a new one
// that implements declared interfaces. The new proxy will retain
// the old target instance, and any of the old introduction instances
// that match the requested interfaces. Any requested interfaces that
// were not 'declared' on the old ProxyConfig, will be satisfied using
// IntroductionFactoryBean's that have been defined for those
// interface names.
Object cast(Object proxy, Class[] interfaces);
}
etc. etc.
I'm sure you get the general idea - simply put, if an Introduction remembers
to actually declare the interface that it 'defines', then you can use
IntroductionFactoryBeans to drive the composition of Proxy's against those
'declared' interfaces.
Now, in the context of the original question about how to define an
IntroductionAdvice, this would suggest that the 'duplication' of a
getDeclaredInterface(), would actually be appropriate. ie:
IntroductionAdvice {
getInterceptor();
getDeclaredInterface();
getClassPointcut();
}
Then a list of IntoductionAdvice's that returned null from getInterceptor(),
would implicitly define an abstract set of mixins - and once the
interceptors were bound, the set would become concrete etc.
From this point, it then becomes a very short step, to allowing the
introduction interceptors to have their own interceptor chains. Then a
mixin becomes a truly composable unit of reuse !
Apologies for the length of this...
Roger
"Rod Johnson" <rod...@in...> wrote in message
news:1fd801c3a608$ce0fff90$3800a8c0@chopin...
> Roger,
>
> The IntroductionAdvice getInterfaces() method would return the same as the
> IntroductionInterceptor getIntroducedInterfaces() method.
>
> So to avoid the duplication, perhaps the IntroductionAdvice methods should
> be:
>
> getIntroductionInterceptor(); // Can get interfaces from this
>
> get[Class]Pointcut();
>
>
> I don't know whether we need an IntroductionAdvice at all. It does make
> sense in that introduction isn't method level, but besides that what does
it
> add?
>
> Renaud, should we consider moving the Spring IntroductionInterceptor to
the
> AOP Alliance intercept package? This seems pretty generic, and not at all
> Spring-specific.
>
> Regarding Renaud's point about pointcuts, perhaps another way would be for
> there to be the following pointcut interfaces, and a total of 3 methods:
>
> interface Pointcut {
>
> // Class filtering for any pointcut
> boolean applies(Class clazz, AttributeRegistry reg);
>
> }
>
> interface MethodPointcut extends Pointcut {
>
> // Must test this as well for a MethodPointcut
> applies(Method, Class, AttributeRegistry);
>
> }
>
> interface DynamicMethodPointcut extends MethodPointcut {
> // same as now, adds knowledge of arguments
> applies(Method, Class, args, AttributeRegistry);
> }
>
>
> This way an optimization could be to invoke the applies(Class) method on a
> pointcut before considering its use on any class.
>
> Regards,
> Rod
>
> ----- Original Message -----
> From: "roger holbrook" <apo...@sn...>
> To: <spr...@li...>
> Sent: Saturday, November 08, 2003 2:43 PM
> Subject: [Springframework-developer] Re: AOP API
>
>
> >
> > Hi Rod
> >
> > Can you expand on the IntroductionAdvice ?
> >
> > > And the new IntroductionAdvice could look as Bob suggested:
> > >
> > > getInterceptor();
> > > getInterfaces();
> > > getClassPointcut();
> > >
> >
> > Does this represent the conditional inclusion of what is currently a
> single
> > IntroductionInterceptor instance into a proxy instance for a given
target
> > class ?
> >
> > I am wondering what the interfaces returned by getInterfaces() represent
> > logically - is this what is currently returned by the method
> > IntroductionInterceptor.getIntroducedInterfaces() or something else ?
> >
> > Roger
> >
> >
> > "Rod Johnson" <rod...@in...> wrote in message
> > news:1f6b01c3a5e1$69ac25a0$3800a8c0@chopin...
> > > Bob,
> > >
> > > You've convinced me. I think a ClassPointcut makes sense, and a
special
> > kind
> > > of IntroductionAdvice is a good idea.
> > >
> > > So I think the Advice interface I proposed earlier could become
> > >
> > > getInterceptor();
> > > getMethodPointcut();
> > > getClassPointcut();
> > >
> > > Either getMethodPointcut() or getClassPointcut() could return null. If
> > both
> > > returned null, the pointcut would always apply. Class pointcut
returning
> > > null means it applies to all classes; method pointcut returning null
> means
> > > it applies to all methods.
> > >
> > > Should this stay called "Advice" or "InterceptionAdvice" as Bob
> suggests?
> > > IntroductionAdvice _is_ interception advice, so maybe just advice is
> > better
> > > for interception advice?
> > >
> > > And the new IntroductionAdvice could look as Bob suggested:
> > >
> > > getInterceptor();
> > > getInterfaces();
> > > getClassPointcut();
> > >
> > > Although we don't do class loading stuff, Spring isn't limited to
advice
> > on
> > > specific proxies because of the new "auto proxying" features, in which
a
> > > BeanPostProcessor can create proxies automagically around any bean.
> > >
> > > Regards,
> > > Rod
> > >
> > > ----- Original Message -----
> > > From: "Bob Lee" <cra...@cr...>
> > > To: <spr...@li...>;
> > > <rod...@in...>
> > > Sent: Friday, November 07, 2003 8:40 PM
> > > Subject: Re: [Springframework-developer] Fw: Memento Pattern
> > >
> > >
> > > > I think having separate class and method pointcuts is important for
> two
> > > > reasons:
> > > >
> > > > 1) Introductions map at class granularity, not method.
> > > >
> > > > 2) Performance. If a pointcut doesn't map to a given class, why
recall
> > > > it for every method?
> > > >
> > > > This doesn't make much of a difference in the scope of a simple
> > > > ProxyFactory. Which interceptors map to which classes is in the code
> > > > that uses the factory. If you want to move to a more generic
factory,
> > > > class pointcuts will be important.
> > > >
> > > > Thanks,
> > > > Bob
> > > >
> > > > Rod Johnson wrote:
> > > >
> > > > >Forwarded on behalf of Bob, who's having problems posting to the
> > list...
> > > > >
> > > > >I think this is actually not dissimilar to what I proposed, with
the
> > > > >IntroductionAdvice corresponding to my Advice.
> > > > >
> > > > >I think the present MethodPointcut can cover both Class and method
> > case.
> > > > >
> > > > >I think we should introduce a new "Pointcut" superinterface for
> > > > >MethodPointcut, even if it's a tag interface at present, and have
> > Advice
> > > > >return Pointcut, not MethodPointcut. Although I don't think Spring
> > should
> > > > >support field interception, and don't much like it in principle, we
> > > > >shouldn't rule options out in our API.
> > > > >
> > > > >I'm inclining towards implementing the Advice interface I
proposed.
> > I'm
> > > not
> > > > >planning to implement the Aspect interface for now, supporting
> multiple
> > > > >Advices in one object, although that can be added later.
> > > > >
> > > > >Regards,
> > > > >Rod
> > > > >
> > > > >----- Original Message -----
> > > > >From: "Bob Lee" <cra...@cr...>
> > > > >To: "Rod Johnson" <rod...@in...>
> > > > >Sent: Friday, November 07, 2003 7:41 PM
> > > > >Subject: Re: Memento Pattern
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >>Rod,
> > > > >>
> > > > >>I keep getting an error when I try to send to the list (detailed
> > below).
> > > > >>
> > > > >>Here's my suggestion for the interfaces:
> > > > >>
> > > > >>interface ClassCut {
> > > > >> boolean appliesTo(Class clazz, ...);
> > > > >>}
> > > > >>
> > > > >>interface MethodCut {
> > > > >> boolean appliesTo(Method method, ...);
> > > > >>}
> > > > >>
> > > > >>interface InterceptionAdvice {
> > > > >> ClassCut getClassCut();
> > > > >> MethodCut getMethodCut();
> > > > >> [Method]Interceptor getInterceptor();
> > > > >>}
> > > > >>
> > > > >>interface IntroductionAdvice {
> > > > >> ClassCut getClassCut();
> > > > >> Class[] getInterfaces();
> > > > >> [Method]Interceptor getInterceptor();
> > > > >>}
> > > > >>
> > > > >>This gives you the separation and orthogonality you need and
leaves
> > the
> > > > >>door open for performance optimization.
> > > > >>
> > > > >>You could refactor out an Advice super interface, but I don't see
> the
> > > > >>benefit.
> > > > >>
> > > > >>Thanks,
> > > > >>Bob
> > > > >>
> > > > >>P.S. I was able to send okay the other day. Here's the mail error:
> > > > >>
> > > > >>Nov 7 14:26:52 server qmail: 1068236812.632418 starting delivery
> 34:
> > > > >>msg 4337993 to remote
> spr...@li...
> > > > >>Nov 7 14:26:52 server qmail: 1068236812.632437 status: local 0/10
> > > > >>remote 1/20
> > > > >>Nov 7 14:27:08 server qmail: 1068236828.373999 delivery 34:
> deferral:
> > > > >>
> > > > >>
> > > > >>
> > > >
> > >
> >
>
>66.35.250.206_does_not_like_recipient./Remote_host_said:_451-Could_not_comp
> > > l
> > > >
> > >
> >
>
>ete_sender_verify_callout/451-Could_not_complete_sender_verify_callout_for_
> > > <
> > > >
> > >
> >
>
>cra...@cr...>./451-The_mail_server(s)_for_the_domain_may_be_tempor
> > > a
> > > >
> > >
> >
>
>rily_unreachable,_or/451-they_may_be_permanently_unreachable_from_this_serv
> > > e
> > > >
> > >
> >
>
>r._In_the_latter_case,/451-you_need_to_change_the_address_or_create_an_MX_r
> > > e
> > > >
> > >
> >
>
>cord_for_its_domain/451-if_it_is_supposed_to_be_generally_accessible_from_t
> > > h
> > > >
> > >
> >
>
>e_Internet./451_Talk_to_your_mail_administrator_for_details./Giving_up_on_6
> > > 6
> > > > >.35.250.206./
> > > > >
> > > > >
> > > > >>I wonder what changed...
> > > > >>
> > > > >>
> > > > >>
> > > > >>
> > > > >>
> > > > >>
> > > > >
> > > > >
> > > > >
> > > > >
> > > > >-------------------------------------------------------
> > > > >This SF.Net email sponsored by: ApacheCon 2003,
> > > > >16-19 November in Las Vegas. Learn firsthand the latest
> > > > >developments in Apache, PHP, Perl, XML, Java, MySQL,
> > > > >WebDAV, and more! http://www.apachecon.com/
> > > > >_______________________________________________
> > > > >Springframework-developer mailing list
> > > > >Spr...@li...
> > > >
> >https://lists.sourceforge.net/lists/listinfo/springframework-developer
> > > > >
> > > > >
> > > >
> > > >
> > > >
> > >
> > >
> > >
> > >
> > > -------------------------------------------------------
> > > This SF.Net email sponsored by: ApacheCon 2003,
> > > 16-19 November in Las Vegas. Learn firsthand the latest
> > > developments in Apache, PHP, Perl, XML, Java, MySQL,
> > > WebDAV, and more! http://www.apachecon.com/
> >
> >
> >
> >
> >
> >
> >
> > -------------------------------------------------------
> > This SF.Net email sponsored by: ApacheCon 2003,
> > 16-19 November in Las Vegas. Learn firsthand the latest
> > developments in Apache, PHP, Perl, XML, Java, MySQL,
> > WebDAV, and more! http://www.apachecon.com/
> > _______________________________________________
> > Springframework-developer mailing list
> > Spr...@li...
> > https://lists.sourceforge.net/lists/listinfo/springframework-developer
> >
>
>
>
>
> -------------------------------------------------------
> This SF.Net email sponsored by: ApacheCon 2003,
> 16-19 November in Las Vegas. Learn firsthand the latest
> developments in Apache, PHP, Perl, XML, Java, MySQL,
> WebDAV, and more! http://www.apachecon.com/
|