[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] pointcut clash (?)

I'm impleting a lazy loader, that is a component that loads complex data 
structures (e.g., lists, hashmaps) only on demand. The idea is that each 
instance variable annotated with a custom annotation is not loaded immediatly 
(as the object construction happens) but only when such variable is accessed.
This is the pointcut that realizes the above:

 pointcut lazyLoaderRequired( LazyLoading loadingProperties, FilteredLoader 
mySelf ) : 
                                    (
                                      get( @LazyLoading 
Collection<StatefullDatabaseObject+>+ StatefullDatabaseObject+.* )              
                                      ||                                                                        
                                      get( @LazyLoading 
Map<SerializableObject+, 
DatabaseObject+>+ SerializableObject+.* )       
                                      ||                                                                                        
                                      get( @LazyLoading 
Map<SerializableObject+, 
StatelessDatabaseObject+>+ SerializableObject+.* )      
                                    )
                                    &&                                                                                          
                                    @annotation( loadingProperties )                                                            
                                    &&                                                                                          
                                    this( mySelf )                                                                              
                                    &&                                                                                          
                                    (! execution( public void 
FilteredLoader.loadFilteredData(Class) ) )                      
                                    &&
                                    (! cflow(adviceexecution()) )
                                    ;


each time I perform a "get" on a complex data structure within a 
StatefullDatabaseObject, the pointcut intercepts such calls. The advice is the 
following:

before( LazyLoading loadingProperties, FilteredLoader mySelf) : 
lazyLoaderRequired( loadingProperties, mySelf)  {
        // perform standard lazy loading
        this.performLazyLoading(loadingProperties, mySelf, false);
        
    }

The idea behing the advice is that each time a "get" happens on a complex data 
structure, the aspect checks an internal cache to see if such complex data 
structure has been loaded yet or not. In the case it has not been loaded it 
loads, otherwise pull it from the cache. The last parameter (false) of the 
performLazyLoading(..) does this: if false searches the cache before loading 
the objects, if true never checks the cache and loads the object (i.e., this 
flag suppresses lazy loading).
All the above works great.

Now there are special cases where I want the lazy loading mechanism to be 
forced, that is the aspect should intercepts particular conditions and force a 
loading of the required complex structures. Such particular cases are all the 
method of the DatabaseDialog+ or all the methods of the QueryElements+. This 
conditions extend the above pointcut definition, and therefore the pointcut 
should be:

 pointcut lazyLoaderForced( LazyLoading loadingProperties, FilteredLoader 
mySelf) : 
                                cflow( lazyLoaderRequired( loadingProperties, 
mySelf) )
                                &&
                                (
                                execution( public boolean 
DatabaseDialog+.perform*() throws 
DatabaseException )
                                ||
                                execution( public JComboBox 
QueryElements.*(..) )
                                ||
                                execution( * DatabaseDialog+.*(..) )
                                
                                
                                )
                                ;


and the corresponding advice should change the suppress-lazy-loading flag:

before( LazyLoading loadingProperties, FilteredLoader mySelf ): 
lazyLoaderForced( loadingProperties, mySelf)  {
        // perform forced lazy loading
        this.performLazyLoading(loadingProperties, mySelf, true);
    }


Now what happens is that, checking with debugger, println, and observing 
program misbehaviour, the lazyLoadingForced advice does not work for 
DatabaseDialog+ and QueryElements+ methods. It is like the lazyLoadingRequired 
works  before the forced one. This is what lead me think there's a pointcut 
clash, but probably I'm doing a wrong pointcut definition.


Luca



On Friday 13 March 2009 19:52:13 Andy Clement wrote:
> Hi Luca,
>
> I'm having a little trouble understanding the configuration - those
> pointcuts are quite complex.
>
> > Now what should happen is that a method of QueryElements is adviced by
> > the lazy loader required pointcut, and eclipse confirms this. However,
> > what
>
> happen
>
> > observing the running code is that the lazyLoaderRequired pointcut is
>
> always
>
> > triggered. I suspect this is due to the fact that two pointcuts are
>
> And this says eclipse confirms a method of QueryElements is advised by the
> lazy loader
> required pointcut and at runtime the lazy loader required pointcut is
> always triggered.  Did
> you mean lazyLoaderForced for one of those?
>
> I'm not sure how you are expecting these two pointcuts to interact at a
> join point - and how
> do you think the second one is overriding the first one? They have
> different names.  You
> can't influence what the first one is doing by writing the second one -
> unless it was around
> advice and the second one happened to have higher precedence and did not
> proceed to the join
> point to drive the lower precedence one.
>
> If you can give a sample of the advised code (or pseudocode for it) and
> what you want to
> achieve, that might help.
>
> The use of cflow is going to cause quite a few markers in AJDT to show up -
> but they will
> all be annotated with a ? indicating the location is advised in the
> bytecode but a decision will
> be made at runtime whether to invoke the advice.
>
> Andy.
>
> 2009/3/13 Luca Ferrari <fluca1978@xxxxxxxxxxx>
>
> > Hi,
> > I'm getting into troubles with an aspect that should drive a lazy loader
> > for
> > complex data types:
> >
> >  pointcut lazyLoaderRequired( LazyLoading loadingProperties,
> > FilteredLoader mySelf ) :
> >                                    (
> >                                      get( @LazyLoading
> > Collection<StatefullDatabaseObject+>+ StatefullDatabaseObject+.* )
> >
> >                                      get( @LazyLoading
> > Map<SerializableObject+,
> > DatabaseObject+>+ SerializableObject+.* )
> >
> >                                      get( @LazyLoading
> > Map<SerializableObject+,
> > StatelessDatabaseObject+>+ SerializableObject+.* )
> >                                    )
> >                                    &&
> >                                    @annotation( loadingProperties )
> >                                    &&
> >                                    this( mySelf )
> >                                    &&
> >                                    (! execution( public void
> > FilteredLoader.loadFilteredData(Class) ) )
> >                                    &&
> >                                    (! cflow(adviceexecution()) )
> >                                    ;
> >
> >
> > the above pointcut intercepts get calls and evaluates if the lazy loading
> > should happen (or not, if it has been already performed):
> >
> > before( LazyLoading loadingProperties, FilteredLoader mySelf) :
> > lazyLoaderRequired( loadingProperties, mySelf)  {
> >        // perform standard lazy loading
> >        this.performLazyLoading(loadingProperties, mySelf, false);
> >
> >    }
> >
> >
> > Now I've got situations where I want lazy loading to be disabled, so I
> > wrote
> > another pointcut that partially override the above one:
> >
> >  pointcut lazyLoaderForced( LazyLoading loadingProperties, FilteredLoader
> > mySelf) :
> >                                cflow( lazyLoaderRequired(
> > loadingProperties, mySelf) )
> >                                &&
> >                                (
> >                                execution( public boolean
> > DatabaseDialog+.perform*() throws
> > DatabaseException )
> >
> >                                withincode( public JComboBox
> > QueryElements.*(..) )
> >
> >                                execution( * DatabaseDialog+.*(..) )
> >
> >
> >                                )
> >                                ;
> >
> > and defined another advice that should be triggered by the above
> > pointcut:
> >
> > before( LazyLoading loadingProperties, FilteredLoader mySelf ):
> > lazyLoaderForced( loadingProperties, mySelf)  {
> >        // perform forced lazy loading
> >        this.performLazyLoading(loadingProperties, mySelf, true);
> >    }
> >
> >
> > Now what should happen is that a method of QueryElements is adviced by
> > the lazy loader required pointcut, and eclipse confirms this. However,
> > what happen
> > observing the running code is that the lazyLoaderRequired pointcut is
> > always
> > triggered. I suspect this is due to the fact that two pointcuts are
> > overlapping, but I've tried also to isolate the statements of a lazy
> > loading
> > required but the program always executes the required pointcut/advice.
> >
> > Any idea about the problem?
> >
> > Thanks,
> > Luca
> > _______________________________________________
> > aspectj-users mailing list
> > aspectj-users@xxxxxxxxxxx
> > https://dev.eclipse.org/mailman/listinfo/aspectj-users