001    /*
002      Copyright (C) 2001-2004 Renaud Pawlak <renaud@aopsys.com>
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public
015      License along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017      USA */
018    
019    package org.objectweb.jac.core;
020    
021    import java.io.FileNotFoundException;
022    import java.io.Serializable;
023    import java.lang.reflect.InvocationTargetException;
024    import java.lang.reflect.Method;
025    import java.util.Arrays;
026    import java.util.Collection;
027    import java.util.HashSet;
028    import java.util.Iterator;
029    import java.util.List;
030    import java.util.Map;
031    import java.util.Set;
032    import java.util.Vector;
033    import org.apache.log4j.Logger;
034    import org.objectweb.jac.core.rtti.*;
035    import org.objectweb.jac.util.WeakHashSet;
036    
037    /**
038     * This class is the root class for the aspect components defined by a
039     * Jac application programmers.
040     * 
041     * <p>When programming a new aspect, the programmer must extends this
042     * class and define new pointcuts to link a set of base method
043     * invocation to a wrapping method. If necessary, the programmer can
044     * also redefine the methods of the interface
045     * <code>BaseProgramListener</code> to be able to react on several
046     * events happenning in the base programm such as object
047     * (de)serialization, object instantiation, object naming, object
048     * cloning, or wrappers execution.
049     *
050     * @author <a href="mailto:pawlak@cnam.fr">Renaud Pawlak</a>
051     *
052     * @see Pointcut */
053    
054    public class AspectComponent 
055        implements Serializable, BaseProgramListener 
056    {
057        static Logger logger = Logger.getLogger("aspects");
058        static Logger loggerConf = Logger.getLogger("aspects.config");
059        static Logger loggerWrap = Logger.getLogger("wrappers");
060        static Logger loggerWuni = Logger.getLogger("wuni");
061        static Logger loggerPerf = Logger.getLogger("perf");
062    
063        protected static final boolean SHARED = false;
064        protected static final boolean NOT_SHARED = true;
065    
066        protected static final ClassRepository cr =  ClassRepository.get();
067    
068        /**
069         * Returns true if the method is defined in the aspect component
070         * class.
071         *
072         * @param methodName the method to test
073         * @return true if aspect component method */
074    
075        public static boolean defines(String methodName) {
076            if (ClassRepository.getDirectMethodAccess(AspectComponent.class, 
077                                                      methodName )[0] != null)
078                return true;
079            return false;
080        }
081    
082        /**
083         * A common configuration method that defines a timer and its
084         * callback.
085         *
086         * <p>The method <code>mi</code> is invoked every
087         * <code>period</code> ms. The method is defined in the aspect
088         * component.
089         *
090         * @param period the timer's period (in ms)
091         * @param callback the method that is called every period 
092         * @param args the arguments the callback is called with */
093    
094        public void defineTimer(final long period, final MethodItem callback, 
095                                final Object[] args) {
096            final AspectComponent ac=this;
097            new Thread() {
098                    public void run() {
099                        while(true) {
100                            try {
101                                sleep(period);
102                            } catch(Exception e) {
103                                e.printStackTrace();
104                            }
105                            callback.invoke(ac,args);
106                        }
107                    }
108                }.start(); 
109        }
110    
111        /**
112         * Tell if the aspect component is already woven to the base
113         * program.<br>
114         *
115         * @see #weave() */
116    
117        //   public boolean woven = false;
118    
119        /** 
120         * Memorize how many calls have been performed on
121         * <code>start_weaving_type.start_weaving_method</code>. The
122         * weaving will start when this number reaches
123         * <code>start_weaving_count</code>.<br>
124         *
125         * @see #weave() */
126    
127        public int firstCall = -1;
128    
129        /** 
130         * The type where the weaving has to start.
131         *
132         * @see #weave() */
133       
134        public Class startWeavingType;
135    
136        /** 
137         * The method where the weaving has to start.<br>
138         *
139         * @see #weave() 
140         */
141        public String startWeavingMethod;
142    
143        /** 
144         * The number of calls of
145         * <code>startWeavingType.startWeavingMethod</code> where the
146         * weaving has to start.<br>
147         *
148         * @see #weave() 
149         */
150        public int startWeavingCount;
151    
152        /**
153         * The number of instance of <code>startWeavingType</code> where
154         * the weaving has to start.<br>
155         *
156         * @see #weave() 
157         */
158        public int startWeavingCCount;
159    
160        /** 
161         * The wrappers handled by this aspect component.<br>
162         *
163         * @see #getWrappers() 
164         * @see #addWrapper(Wrapper) 
165         */
166        protected transient WeakHashSet wrappers;
167    
168        /**
169         * Tells if this aspect component is a system listener one so that
170         * it can receive events from the org.objectweb.jac.core objects. 
171         */
172        protected boolean systemListener = false;
173    
174        /**
175         * Sets this aspect component to be a system or non-system
176         * listener.
177         *
178         * @param systemListener if true, the component can receive events
179         * from the JAC core objects (e.g. whenUsingNewInstance) ; if
180         * false, these events are filtered 
181         */
182        public void setSystemListener(boolean systemListener) {
183            this.systemListener = systemListener;
184        }
185    
186        /**
187         * Tells if this aspect component is a system listener.
188         *
189         * @return true if system listener
190         * @see #setSystemListener(boolean) 
191         */
192        public boolean isSystemListener() {
193            return systemListener;
194        }
195    
196        /**
197         * The default constructor of the aspect component. By default,
198         * there is no start weaving type or method so that the
199         * <code>weave()</code> is called as the aspect component is
200         * registering to the aspect component manager<br>. 
201         *
202         * @see #weave()
203         * @see ACManager#register(String,Object) 
204         */
205        public AspectComponent() {   
206            logger.debug("New AC: "+this);
207            wrappers = new WeakHashSet();
208            firstCall = -1;
209            startWeavingType = null;
210            startWeavingMethod = null;
211            startWeavingCount = 0;
212            startWeavingCCount = 0;
213            init();
214            //      Collaboration.get().setCurAC(ACManager.get().getName(this));
215        }
216    
217        /**
218         * Initializes the aspect component so that its state is resetted
219         * to the default state.<br> 
220         */
221        public void init() {      
222            //woven = false;
223            loggerWrap.debug("clearing wrappers (was "+wrappers+")");
224            wrappers.clear();
225        }
226    
227        protected String application=null;
228    
229        /**
230         * Gets the application that declares this aspect component.
231         * 
232         * @return the application's name
233         * @see Application
234         * @see ApplicationRepository 
235         */
236        public String getApplication() {
237            return application;
238        }
239    
240        /**
241         * Gets the application that declares this aspect component.
242         *
243         * <p>This method is invoked by the system and should not be
244         * directly used.
245         * 
246         * @param application the application's name
247         * @see Application
248         * @see ApplicationRepository */
249    
250        public void setApplication(String application) {
251            this.application = application;
252        }
253    
254        /**
255         * Returns the wrappers handled by this aspect component. When you
256         * have a reference on a wrapper, you can also know which aspect
257         * component is currently handling it by using
258         * <code>Wrapper.getAspectComponent()</code>.<br>
259         *
260         * @return a vector containing the handdled wrappers
261         * @see #addWrapper(Wrapper)
262         * @see Wrapper#getAspectComponent() */
263       
264        public Collection getWrappers() {
265            return wrappers;
266        }
267       
268        /**
269         * Add a wrapper to the wrappers handled by this aspect
270         * component.
271         * 
272         * <p>The programmer should not call this method explicitly unless
273         * s/he really hnows what s/he is doing.  In fact, this method is
274         * automatically upcalled when the aspect component wraps a base
275         * program object (see <code>Wrappee.wrap()</code>).<br>
276         *
277         * @param wrapper the wrapper to add to the handdled wrappers
278         * @see #getWrappers()
279         * @see Wrapping#wrap(Wrappee,Wrapper,AbstractMethodItem) 
280         */
281    
282        public void addWrapper(Wrapper wrapper) {
283            wrappers.add(wrapper);
284        }
285    
286        /**
287         *  The programmer should define this method to wrap all the
288         *  currently instantiated Jac objects so that it plugs a given
289         *  aspect. Since the objects might allready be wrapped by other
290         *  weavers, the programmer should be careful that it does not wrap
291         *  the same object with the same wrapper several times. This can
292         *  be done in the weave function by using the
293         *  <code>Wrappee.isExtendedBy()</code> method. When a new AC is
294         *  registered the weave method is automatically called. In the
295         *  jac.prop file, the time when it is called can be parametrized
296         *  with the org.objectweb.jac.startWeavingPlaces property.
297         *
298         *  <p>This method is only called once. For the objects that are
299         *  created after the weaving, the programmer must define the
300         *  <code>whenUsingNewInstance</code> method to wrap them.
301         *
302         *  <p>The default implementation of the weave method is the
303         *  following. In most of the case, it will work if the
304         *  <code>whenUsingNewInstance()</code> is correctly defined (thus,
305         *  the programer do not have to redefine the weave method).
306         *
307         *  <ul><pre>
308         *  for (int i=0; i < JacObject.objectCount(); i++) {
309         *     simulateUsingNewInstance ( (Wrappee)JacObject.getObject(i) );
310         *  }
311         *  </pre></ul>
312         *
313         *  <b>IMPORTANT NOTE</b>: this method is not deprecated but the
314         *  programmer should not overload it since it is much cleaner to
315         *  define the <code>whenUsingNewInstance()</code> to implement the
316         *  weaving.<br>
317         *
318         * @see #whenUsingNewInstance(Interaction)
319         * @see #simulateUsingNewInstance(Wrappee)
320         * @see Wrapping#isExtendedBy(Wrappee,ClassItem,Class) 
321         */
322    
323        public void weave() {
324            Iterator it = ObjectRepository.getMemoryObjects().iterator();
325            while (it.hasNext()) {
326                simulateUsingNewInstance((Wrappee)it.next());
327            }
328        }
329    
330        /**
331         * This method is called when a new instance (that has not been
332         * wrapped by the aspect component yet) is used by a peer
333         * object.
334         * 
335         * <p>By default, this method check out all the pointcuts that have
336         * been defined within this aspect component and accordingly wraps
337         * the wrappee.
338         * 
339         * <p>However, for performance or flexibility reasons, the
340         * programmer can also define it from scratch so that the aspects
341         * can dynamically apply while the base program creates new base
342         * objects. The aspect component is notified only once for each new
343         * instance.
344         * 
345         * <p>Here is a typical implementation of this method for a
346         * many-to-one wrappees-wrapper relationship:
347         *
348         * <ul><pre>
349         * public class MyAC extends AspectComponent {
350         *   public MyWrapper myWrapper = null;
351         *   public void whenUsingNewInstance() {
352         *     // creates the sole instance of MyWrapper
353         *     if ( myWrapper == null ) myWrapper = new MyWrapper();
354         *     // make sure we do not wrap an object several times 
355         *     // (this is usually not useful!!)
356         *     if ( wrappee().isExtendedBy( MyWrapper.class ) ) return;
357         *     // Do not wrap system or aspect objects
358         *     if ( wrappee().getClass().getName().startsWith( "org.objectweb.jac.core." ) ||
359         *          wrappee().getClass().getName().startsWith( "org.objectweb.jac.aspects." ) ) 
360         *       return;
361         *     // wrap it...
362         *     wrappee().wrapAll( myWrapper, "myWrappingMethod" );
363         *   }
364         * }
365         * </pre></ul>
366         *
367         * <p>The same but with one-to-one wrappees-wrappers
368         * relationship:
369         *
370         * <ul><pre>
371         * public class MyAC extends AspectComponent {
372         *   public void whenUsingNewInstance() {
373         *     // make sure we do not wrap an object several times 
374         *     // (this is usually not useful!!)
375         *     if ( wrappee().isExtendedBy( MyWrapper.class ) ) return;
376         *     // Do not wrap system or aspect objects
377         *     if ( wrappee().getClass().getName().startsWith( "org.objectweb.jac.core." ) ||
378         *          wrappee().getClass().getName().startsWith( "org.objectweb.jac.aspects." ) ) 
379         *       return;
380         *     // one wrapper for each new instance
381         *     MyWrapper myWrapper = new MyWrapper();
382         *     // wrap it...
383         *     wrappee().wrapAll( myWrapper, "myWrappingMethod" );
384         *   }
385         * }
386         * </pre></ul>
387         *
388         * <b>NOTE</b>: this method is not upcalled until the aspect component
389         * is woven.<br>
390         * 
391         * @see #weave() 
392         */
393        public void whenUsingNewInstance(Interaction interaction) {
394            //if(treatedInstances.contains(wrappee())) return;
395            //treatedInstances.add(wrappee());
396            ClassItem cli = interaction.getClassItem();
397            //Log.trace("wuni",this+": "+method());
398            AbstractMethodItem method = interaction.method;
399    
400            loggerWuni.debug("whenUsingNewInstance("+interaction+"); pointcuts: "+pointcuts.size());
401            int i = 0;
402            Iterator it = pointcuts.iterator();
403            while (it.hasNext()) {
404                loggerWuni.debug("  pointcut "+i++);
405                ((Pointcut)it.next()).applyTo(interaction.wrappee, cli);
406            }
407        }
408    
409        public void whenUsingNewClass(ClassItem cli) {
410            Iterator it = pointcuts.iterator();
411            int i = 0;
412            loggerWuni.debug(this+".whenUsingNewClass"+cli);
413            while (it.hasNext()) {
414                ((Pointcut)it.next()).applyTo(null, cli);
415            }
416        }
417    
418        /**
419         * This method simulates an instance first use so that the system
420         * upcalls <code>whenUsingNewInstance()</code> with a fake
421         * collaboration point (<code>method()</code> is null and
422         * <code>args</code> is null too).
423         *
424         * @param wrappee the wrappe on which the call is simulated.
425         * @see #whenUsingNewInstance(Interaction) */
426    
427        protected void simulateUsingNewInstance(Wrappee wrappee) {
428            /** simulates a new interaction */
429            //      Log.trace("core","simulateUsingNewInstance "+this);
430            Collaboration collab = Collaboration.get();
431            //collab.newInteraction();
432            whenUsingNewInstance(new Interaction(null,wrappee,null,null));
433            /** end of simulated interaction */
434            //collab.endOfInteraction();
435        }
436    
437        /**
438         * This method is called when a new instance is created.
439         * 
440         * <p>Since the instance is not initialized yet, the aspect
441         * component must not wrap it at this stage. To wrap a new
442         * instance, the aspect component must use the
443         * <code>whenUsingNewInstance()</code> method. This method is not
444         * upcalled when the instantiation is remotly performed (from a
445         * deployer site), see the <code>whenRemoteInstantiation()</code>
446         * method.<br>
447         *
448         * @param newInstance the newly created instance
449         * @see #whenUsingNewInstance(Interaction)
450         * @see #whenRemoteInstantiation(Wrappee,String) */
451    
452        //public void whenNewInstance( Wrappee newInstance ) {}
453    
454        /**
455         * This method is upcalled when a new object is instanciated from a
456         * remote site.
457         *
458         * <p>The name that is passed is the name of the remote
459         * reference that has been used to create the object. Typically, it
460         * is the name that will be used by the naming aspect to name the
461         * new object.
462         * 
463         * @param newInstance the instance that have been created by a
464         * remote host
465         * @param name the name of the new instance
466         * @see org.objectweb.jac.aspects.naming.NamingAC#whenRemoteInstantiation(Wrappee,String) 
467         */
468        public void whenRemoteInstantiation(Wrappee newInstance,
469                                            String name) {}
470    
471        /**
472         * This method unwraps all the instances that have been wrapped by
473         * the aspect component.
474         * 
475         * <p>This is done in a generic way that is not very efficient. To
476         * optimize this process, the user may overload the
477         * <code>unweave()</code> method to change its default
478         * behavior.<br>
479         *
480         * @see #unweave() 
481         */
482        protected final void unwrapAll() {
483            loggerWrap.debug("unwrap all");
484            loggerWrap.debug(wrappers.size()+" wrappers: " + wrappers);
485            Iterator it = ObjectRepository.getMemoryObjects().iterator();
486            while (it.hasNext()) {
487                Object o = it.next();
488                if (o instanceof Wrappee) {
489                    Wrappee wrappee = (Wrappee)o;
490                    ClassItem wrappeeClass = cr.getClass(wrappee);
491                    loggerWrap.debug("testing wrappee " + wrappee);
492                    Wrapping.unwrap(wrappee,wrappeeClass,wrappers);
493                    Wrapping.unwrap(null,wrappeeClass,wrappers);
494                }
495            }
496            wrappers.clear();
497        }
498    
499        /**
500         * The programmer should overload this method to unwrap all the
501         * currently wrapped Jac objects so that it unplugs a given aspect.
502         * 
503         * <p>By default, calls the <code>unwrapAll</code> method but the
504         * programmer can implement the unveaving process in a more
505         * efficient way.<br>
506         *
507         * @see #unwrapAll() */
508    
509        public void unweave() {
510            logger.info("--- unweaving "+this+" ---");
511                    long start = System.currentTimeMillis();        
512            unwrapAll();
513            pointcuts.clear();
514            loggerPerf.info("unweaved "+this+" in "+(System.currentTimeMillis()-start)+"ms");
515        }
516    
517        /**
518         * This method is automatically called when a Jac Object is
519         * cloned. */
520    
521        public void whenClone(Wrappee cloned, Wrappee clone) {}
522    
523        /**
524         * This method is called when a JAC object is serialized and can
525         * parametrize the serialization by filling the <code>finalObject</code>
526         * parameter.
527         *
528         * <p><b>IMPORTANT</b>: this method is upcalled only if the
529         * serialization is done with a
530         * <code>JacObjectOutputStream</code>. To ensure the correct use of
531         * this class, only use <code>JacObject.serialize()</code> to
532         * serialize an object.</p>
533         *
534         * @param orgObject the object being serialized
535         * @param finalObject the corresponding serialized structure
536         * @return the object being serialized (usually orgObject, but not
537         * necessarily).
538         * @see SerializedJacObject
539         * @see JacObjectOutputStream */
540    
541        public Wrappee whenSerialized(Wrappee orgObject, 
542                                      SerializedJacObject finalObject) {
543            return orgObject;
544        }
545    
546        /**
547         * This method is called when a base object is deserialized and can
548         * parametrize the deserialization by reading the
549         * SerializedJacObject instance to get some extra infos on the
550         * aspects.
551         *
552         * <p><b>IMPORTANT</b>: this method is upcalled only if the
553         * deserialization is done with a
554         * <code>JacObjectInputStream</code>. To ensure the correct use of
555         * this class, only use <code>JacObject.deserialize()</code> to
556         * deserialize an object.
557         *
558         * @param orgObject the corresponding serialized structure
559         * @param finalObject the object being deserialized
560         * @return the object being deserialized (usually finalObject but
561         * not necessarily)
562         * @see SerializedJacObject
563         * @see JacObjectInputStream */
564    
565        public Wrappee whenDeserialized(SerializedJacObject orgObject, 
566                                        Wrappee finalObject) {
567            return finalObject;
568        }
569    
570    
571        public void onExit() {}
572    
573        /**
574         * This method is called when a wrapper is going to be applied to a
575         * wrappee.
576         *
577         * <p>By overloading this method, the aspect component can skip the
578         * wrapper, for instance if the current collaboration shows that
579         * the wrapper has allready been applied.<br>
580         *
581         * <p>If the method returns true, then the wrapper is run, else it
582         * is skipped. Default: return true.<br>
583         *
584         * @param wrapper the wrapper that is going to be runned
585         * @param wrappingMethod the name of the may-be runned wrapping
586         * method
587         * @return a boolean that tells if the wrapper has to be runned
588         * (true) or not (false)
589         * @see Wrappee
590         * @see Wrapping#wrap(Wrappee,Wrapper,AbstractMethodItem)
591         * @see Wrapper
592         * @see Wrapper#proceed(Invocation) 
593         */
594        public boolean beforeRunningWrapper(Wrapper wrapper, 
595                                            String wrappingMethod) {
596            return true;
597        }
598       
599        /**
600         * This method is called after the application of the
601         * wrapper.
602         *
603         * <p>Typically, the aspect component can set an attribute to
604         * the collaboration that indicates that the wrapper has been
605         * applied (and that can be used by the beforeRunningWrapper
606         * method).
607         * 
608         * @param wrapper the wrapper that has just been runned
609         * @param wrappingMethod the name of the runned wrapping method
610         * @see Wrappee
611         * @see Wrapping#wrap(Wrappee,Wrapper,AbstractMethodItem)
612         * @see Wrapper
613         * @see Wrapper#proceed(Invocation) 
614         */
615        public void afterRunningWrapper(Wrapper wrapper, 
616                                        String wrappingMethod) {}
617    
618        /**
619         * This method is called after a new wrapper wraps a wrappee.
620         */
621    
622        public void afterWrap(Wrappee wrappee, Wrapper wrapper,
623                              String[] wrapping_methods,
624                              String[][] wrapped_methods) {}
625       
626        /**
627         * This method is called when a program gets a set of object from
628         * the object repository.
629         *
630         * <p>At this step, the aspect can change the returned list so that
631         * the program will see the right set of objects (for instance a
632         * security aspect may filter this set so that the user will not
633         * see the objects s/he is not allowed to see or a persistance
634         * aspect may force the load of a set of objects from the storage
635         * and add them to the list).
636         *
637         * @param objects the returned list (can be modified)
638         * @param cl the class that was used by the program to filter its
639         * instances (can be null for all the objects)
640         * @see ObjectRepository */
641    
642        public void whenGetObjects(Collection objects, ClassItem cl) {}
643    
644        public String whenNameObject(Object object,String name) { 
645            return name;
646        }
647    
648        public void getNameCounters(Map counters) {
649        }
650    
651        public void updateNameCounters(Map counters) {
652        }
653    
654        /**
655         * This method is upcalled by JAC when an object was seeked into
656         * the name repository and was not found.
657         *
658         * <p>The reason of this miss can be multiple. For instance, the
659         * persistence aspect may have not already load the object from the
660         * storage, or the distribution aspect may need to bind to a remote
661         * object. Thus, this method allows the aspects to resolve the
662         * object.
663         *
664         * <p>By default, this method does nothing.
665         *
666         * <p>The final choosen name is a contextual attribute called
667         * FOUND_OBJECT.
668         *
669         * @param name the name of the object 
670         * @see BaseProgramListener#FOUND_OBJECT
671         */
672       
673        public void whenObjectMiss(String name) {}
674    
675        public void whenDeleted(Wrappee object) {}
676    
677        public void whenFree(Wrappee object) {}
678    
679        public void afterApplicationStarted() {}
680    
681        public void whenCloseDisplay(Display display) {}
682    
683        public void whenTopologyChanged() {}
684    
685        /**
686         * Called when the aspect's configuration is reloaded
687         */
688        public void whenReload() {}
689        public void beforeReload() {}
690    
691        /**
692         * This method should be defined by the programmer when specific
693         * actions are needed once the aspect component has be
694         * configured. */
695    
696        public void whenConfigured() {}
697    
698        /**
699         * To overload in order to perform some treatements before the
700         * configuration. */
701        public void beforeConfiguration() throws Exception {
702        }
703    
704        public String getName() {
705            return ACManager.getACM().getName(this);
706        }
707    
708        /**
709         * This method is upcalled by the system when the aspect is
710         * actually registered in the AC manager.
711         *
712         * <p>Here it does nothing. */
713        public void doRegister() {
714        }
715    
716        /**
717         * This method is upcalled by the system when the aspect is
718         * actually registered in the AC manager.
719         *
720         * <p>Here it does nothing. */
721        public void doUnregister() {
722        }
723    
724        /** Store the pointcuts. */
725        Vector pointcuts = new Vector();
726    
727        /**
728         * Defines and adds a new method pointcut.
729         *
730         * <p>For more details on how to use pointcuts, see the
731         * <code>MethodPointcut</code> class.
732         *
733         * @param wrappeeExpr the wrappee definition that matches the names
734         * as defined by the naming aspect
735         * @param wrappeeClassExpr the wrappee class expression (matches
736         * the fully qualified class name)
737         * @param wrappeeMethodExpr the wrappee method expression (matches
738         * the full method name as defined by the rtti)
739         * @param wrappingClassName the name of the wrapper class
740         * @param one2one true if each new wrapped instance corresponds to
741         * one different wrapper
742         * @see MethodPointcut 
743         */
744        public Pointcut pointcut(String wrappeeExpr, 
745                                 String wrappeeClassExpr, 
746                                 String wrappeeMethodExpr,
747                                 String wrappingClassName,
748                                 String exceptionHandler,
749                                 boolean one2one) {
750    
751            MethodPointcut pc = new MethodPointcut( this,
752                                                    wrappeeExpr, 
753                                                    wrappeeClassExpr, 
754                                                    wrappeeMethodExpr,
755                                                    null,
756                                                    wrappingClassName,
757                                                    null,
758                                                    null,
759                                                    "ALL",
760                                                    exceptionHandler,
761                                                    one2one );
762            pointcuts.add(pc);
763            return pc;
764        }
765    
766        /**
767         * Defines and adds a new method pointcut.
768         *
769         * <p>For more details on how to use pointcuts, see the
770         * <code>MethodPointcut</code> class.
771         *
772         * @param wrappeeExpr the wrappee definition that matches the names
773         * as defined by the naming aspect
774         * @param wrappeeClassExpr the wrappee class expression (matches
775         * the fully qualified class name)
776         * @param wrappeeMethodExpr the wrappee method expression (matches
777         * the full method name as defined by the rtti)
778         * @param wrappingClassName the name of the wrapper class
779         * @param initParameters the initialization parameters of the
780         * wrapper (passed to the wrappers constructor that matches the
781         * parameters types)
782         * @param one2One true if each new wrapped instance corresponds to
783         * one different wrapper
784         * @see MethodPointcut 
785         */
786        public Pointcut pointcut(String wrappeeExpr, 
787                                 String wrappeeClassExpr, 
788                                 String wrappeeMethodExpr,
789                                 String wrappingClassName,
790                                 Object[] initParameters,
791                                 String exceptionHandler,
792                                 boolean one2One) {
793    
794            MethodPointcut pc = new MethodPointcut( this,
795                                                    wrappeeExpr, 
796                                                    wrappeeClassExpr, 
797                                                    wrappeeMethodExpr,
798                                                    null,
799                                                    wrappingClassName,
800                                                    null,
801                                                    initParameters,
802                                                    "ALL",
803                                                    exceptionHandler,
804                                                    one2One );
805            pointcuts.add(pc);
806            return pc;
807        }
808    
809        /**
810         * Defines and adds a new localized method pointcut.
811         *
812         * <p>For more details on how to use pointcuts, see the
813         * <code>MethodPointcut</code> class.
814         *
815         * @param wrappeeExpr the wrappee definition that matches the names
816         * as defined by the naming aspect
817         * @param wrappeeClassExpr the wrappee class expression (matches
818         * the fully qualified class name)
819         * @param wrappeeMethodExpr the wrappee method expression (matches
820         * the full method name as defined by the rtti)
821         * @param wrappingClassName the name of the wrapper class
822         * @param hostExpr a regular expression that macthes the hosts
823         * where the pointcut has to be applied (if null or empty string,
824         * default is ".*" which means that the pointcut will be applied on
825         * all the hosts)
826         * @param one2One true if each new wrapped instance corresponds to
827         * one different wrapper
828         * @see MethodPointcut */
829    
830        public Pointcut pointcut(String wrappeeExpr, 
831                                 String wrappeeClassExpr, 
832                                 String wrappeeMethodExpr,
833                                 String wrappingClassName,
834                                 String hostExpr,
835                                 String exceptionHandler,
836                                 boolean one2One) {
837    
838            MethodPointcut pc = new MethodPointcut(this,
839                                                   wrappeeExpr, 
840                                                   wrappeeClassExpr, 
841                                                   wrappeeMethodExpr,
842                                                   null,
843                                                   wrappingClassName,
844                                                   null,
845                                                   null,
846                                                   hostExpr,
847                                                   exceptionHandler,
848                                                   one2One);
849            pointcuts.add(pc);
850            return pc;
851        }
852    
853        /**
854         * Defines and adds a new localized method pointcut.
855         *
856         * <p>For more details on how to use pointcuts, see the
857         * <code>MethodPointcut</code> class.
858         *
859         * @param wrappeeExpr the wrappee definition that matches the names
860         * as defined by the naming aspect
861         * @param wrappeeClassExpr the wrappee class expression (matches
862         * the fully qualified class name)
863         * @param wrappeeMethodExpr the wrappee method expression (matches
864         * the full method name as defined by the rtti)
865         * @param wrappingClassName the name of the wrapper class
866         * @param initParameters the initialization parameters of the
867         * wrapper (passed to the wrappers constructor that matches the
868         * parameters types)
869         * @param hostExpr a regular expression that macthes the hosts
870         * where the pointcut has to be applied (if null or empty string,
871         * default is ".*" which means that the pointcut will be applied on
872         * all the hosts)
873         * @param one2One true if each new wrapped instance corresponds to
874         * one different wrapper
875         * @see MethodPointcut 
876         */
877        public Pointcut pointcut(String wrappeeExpr, 
878                                 String wrappeeClassExpr, 
879                                 String wrappeeMethodExpr,
880                                 String wrappingClassName,
881                                 Object[] initParameters,
882                                 String hostExpr,
883                                 String exceptionHandler,
884                                 boolean one2One) {
885          
886            MethodPointcut pc = new MethodPointcut(this,
887                                                   wrappeeExpr, 
888                                                   wrappeeClassExpr, 
889                                                   wrappeeMethodExpr,
890                                                   null,
891                                                   wrappingClassName,
892                                                   null,
893                                                   initParameters,
894                                                   hostExpr,
895                                                   exceptionHandler,
896                                                   one2One);
897            pointcuts.add(pc);
898            return pc;
899        }
900    
901        /**
902         * Defines and adds a new method pointcut.
903         *
904         * <p>For more details on how to use pointcuts, see the
905         * <code>MethodPointcut</code> class.
906         *
907         * @param wrappeeExpr the wrappee definition that matches the names
908         * as defined by the naming aspect
909         * @param wrappeeClassExpr the wrappee class expression (matches
910         * the fully qualified class name)
911         * @param wrappeeMethodExpr the wrappee method expression (matches
912         * the full method name as defined by the rtti)
913         * @param wrapper the wrapper that contains the wrapping method,
914         * cannot be null
915         *
916         * @see MethodPointcut 
917         */
918        public Pointcut pointcut(String wrappeeExpr, 
919                                 String wrappeeClassExpr, 
920                                 String wrappeeMethodExpr,
921                                 Wrapper wrapper,
922                                 String exceptionHandler) {
923    
924            MethodPointcut pc = new MethodPointcut(this,
925                                                   wrappeeExpr, 
926                                                   wrappeeClassExpr, 
927                                                   wrappeeMethodExpr,
928                                                   wrapper,
929                                                   wrapper.getClass().getName(),
930                                                   null,
931                                                   null,
932                                                   "ALL",
933                                                   exceptionHandler,
934                                                   false);
935            pointcuts.add(pc);
936            return pc;
937        }
938    
939        /**
940         * Defines and adds a new localized method pointcut.
941         *
942         * <p>For more details on how to use pointcuts, see the
943         * <code>MethodPointcut</code> class.
944         *
945         * @param wrappeeExpr the wrappee definition that matches the names
946         * as defined by the naming aspect
947         * @param wrappeeClassExpr the wrappee class expression (matches
948         * the fully qualified class name)
949         * @param wrappeeMethodExpr the wrappee method expression (matches
950         * the full method name as defined by the rtti)
951         * @param wrapper the wrapper that contains the wrapping method,
952         * cannot be null
953         * @param hostExpr a regular expression that macthes the hosts
954         * where the pointcut has to be applied (if null or empty string,
955         * default is ".*" which means that the pointcut will be applied on
956         * all the hosts)
957         *
958         * @see MethodPointcut 
959         */
960        public Pointcut pointcut(String wrappeeExpr, 
961                                 String wrappeeClassExpr, 
962                                 String wrappeeMethodExpr,
963                                 Wrapper wrapper,
964                                 String hostExpr,
965                                 String exceptionHandler) {
966    
967            MethodPointcut pc = new MethodPointcut(this,
968                                                   wrappeeExpr, 
969                                                   wrappeeClassExpr, 
970                                                   wrappeeMethodExpr,
971                                                   wrapper,
972                                                   wrapper.getClass().getName(),
973                                                   null,
974                                                   null,
975                                                   hostExpr,
976                                                   exceptionHandler,
977                                                   false);
978            pointcuts.add(pc);
979            return pc;
980        }
981    
982        /**
983         * Defines and adds a new pointcut that upcalls an aspect method
984         * when the matching object is created.
985         *
986         * <p>For more details on how to use pointcuts, see the
987         * <code>MethodPointcut</code> class.
988         *
989         * @param wrappeeExpr the wrappee definition that matches the names
990         * as defined by the naming aspect
991         * @param wrappeeClassExpr the wrappee class expression (matches
992         * the fully qualified class name)
993         * @param methodName a method of the aspect component to call
994         * @param methodArgs the arguments of this methods when called
995         * @see MethodPointcut */
996    
997        public Pointcut pointcut(String wrappeeExpr, 
998                                 String wrappeeClassExpr, 
999                                 String methodName,
1000                                 Object[] methodArgs,
1001                                 String exceptionHandler) {
1002    
1003            MethodPointcut pc = new MethodPointcut(this,
1004                                                   wrappeeExpr, 
1005                                                   wrappeeClassExpr, 
1006                                                   null,
1007                                                   null,
1008                                                   null,
1009                                                   methodName,
1010                                                   methodArgs,
1011                                                   "ALL",
1012                                                   exceptionHandler,
1013                                                   false);
1014            pointcuts.add(pc);
1015            return pc;
1016        }
1017    
1018        /**
1019         * Defines and adds a new localized pointcut that upcalls an aspect
1020         * method when the matching object is created.
1021         *
1022         * <p>For more details on how to use pointcuts, see the
1023         * <code>MethodPointcut</code> class.</p>
1024         *
1025         * @param wrappeeExpr the wrappee definition that matches the names
1026         * as defined by the naming aspect
1027         * @param wrappeeClassExpr the wrappee class expression (matches
1028         * the fully qualified class name)
1029         * @param methodName a method of the aspect component to call
1030         * @param methodArgs the arguments of this methods when called
1031         * @see MethodPointcut */
1032    
1033        public Pointcut pointcut(String wrappeeExpr, 
1034                                 String wrappeeClassExpr, 
1035                                 String methodName,
1036                                 Object[] methodArgs,
1037                                 String hostExpr,
1038                                 String exceptionHandler) {
1039    
1040            MethodPointcut pc = new MethodPointcut(this,
1041                                                   wrappeeExpr, 
1042                                                   wrappeeClassExpr, 
1043                                                   null,
1044                                                   null,
1045                                                   null,
1046                                                   methodName,
1047                                                   methodArgs,
1048                                                   hostExpr,
1049                                                   exceptionHandler,
1050                                                   false);
1051            pointcuts.add(pc);
1052            return pc;
1053        }
1054     
1055        /**
1056         * Generic config method to set an attribute on a class
1057         * @param cli the class to set an attribute on
1058         * @param name name of the attribute
1059         * @param value string value of the attribute
1060         */
1061        public void setAttribute(ClassItem cli, String name, String value) {
1062            cli.setAttribute(name,value);
1063        }
1064    
1065        /**
1066         * Generic config method to set an attribute on a class
1067         * @param field the field to set an attribute on
1068         * @param name name of the attribute
1069         * @param value string value of the attribute
1070         */
1071        public void setAttribute(FieldItem field, String name, String value) {
1072            field.setAttribute(name,value);
1073        }
1074    
1075    
1076        /**
1077         * Generic config method to set an attribute on a method
1078         * @param method the method to set an attribute on
1079         * @param name name of the attribute
1080         * @param value string value of the attribute
1081         */
1082        public void setAttribute(AbstractMethodItem method, 
1083                                 String name, String value) {
1084            method.setAttribute(name,value);
1085        }
1086    
1087        // following methods implement the CollaborationParticipant interface
1088    
1089        public final void attrdef(String name, Object value) {
1090            Collaboration.get().addAttribute( name, value );
1091        }
1092    
1093        public final Object attr( String name ) {
1094            return Collaboration.get().getAttribute( name );
1095        }
1096    
1097        /** Block keywords which can be used instead of "block" */
1098        protected String[] blockKeywords = new String[0];
1099    
1100        public Set getBlockKeywords() {
1101            return new HashSet(Arrays.asList(blockKeywords));
1102        }
1103    
1104        /** Returns defaults configuration files that must be loaded before
1105            the user's configuration */
1106        public String[] getDefaultConfigs() {
1107            return new String[0];
1108        }
1109    
1110        /**
1111         * Returns all the configuration methods of the aspect
1112         * @return Collection of MethodItem
1113         */
1114        public Collection getConfigurationMethods() {
1115            Vector result = new Vector();
1116            Iterator ms = cr.getClass(getClass()).getAllMethods().iterator();
1117    
1118            while(ms.hasNext()){
1119                MethodItem methodItem=(MethodItem)ms.next();
1120                if (isConfigurationMethod(methodItem.getActualMethod())){
1121                    result.add(methodItem);
1122                }
1123            }
1124            return result;
1125        }
1126    
1127        /**
1128         * Returns all the name of the configuration methods of the aspect
1129         * @return Collection of String
1130         */
1131        public Collection getConfigurationMethodsName() {
1132            Vector result = new Vector();
1133            Method[] ms = getClass().getMethods();
1134            for(int i=0;i<ms.length;i++) {
1135                if (isConfigurationMethod(ms[i])) {
1136                    result.add(ms[i].getName());
1137                }
1138            }
1139            return result;
1140        }
1141    
1142    
1143        /**
1144         * Returns all the configuration methods of the aspect whose first
1145         * parameter is compatible with a given type.
1146         * @param firstParamType the type the first parameter must be compatible with
1147         * @return a collection of MethodItem with at least one parameter,
1148         * and whose first parameter can be of type firstParamType or a
1149         * subclass of firstParamType */
1150        public List getConfigurationMethodsName(Class firstParamType) {
1151            Vector result = new Vector();
1152            Iterator ms = cr.getClass(getClass())
1153                .getAllMethods().iterator();
1154            // We use hash set to remove duplicate entries quickly
1155            HashSet names = new HashSet();
1156    
1157            while (ms.hasNext()) {
1158                MethodItem methodItem = (MethodItem)ms.next();
1159                if (isConfigurationMethod(methodItem.getActualMethod())) {
1160                    Class[] paramTypes = methodItem.getParameterTypes();
1161                    if (paramTypes.length>0 &&
1162                        (paramTypes[0].isAssignableFrom(firstParamType) || 
1163                         firstParamType.isAssignableFrom(paramTypes[0])) &&
1164                        !names.contains(methodItem.getName())) {
1165                        result.add(methodItem.getName());
1166                        names.add(methodItem.getName());
1167                    }
1168                }
1169            }
1170            return result;
1171        }
1172    
1173    
1174        /**
1175         * Tells wether a method is configuration method of this aspect
1176         * @param method
1177         * @return true if the method was a configuration method.
1178         */
1179        public boolean isConfigurationMethod(Method method) {
1180            Class cl = method.getDeclaringClass();
1181            if (AspectComponent.class.isAssignableFrom(cl)) {
1182                Class[] interfs=cl.getInterfaces();
1183                for(int i=0;i<interfs.length;i++) {
1184                    if (!interfs[i].getName().endsWith("Conf")) 
1185                        continue;
1186                    Method[] ms = interfs[i].getMethods();
1187                    for(int j=0; j<ms.length; j++) {
1188                        if (ms[j].getName().equals(method.getName())) {
1189                            return true;
1190                        }
1191                    }
1192                }
1193            }
1194            return false;
1195        }   
1196    
1197        protected ConfigMethod currentConfigMethod;
1198        protected Imports currentImports;
1199    
1200        /**
1201         * Configures this aspect component with a given configuration file. 
1202         *
1203         * @param name name of the aspect component (informative)
1204         * @param filePath path to a resource of file containing the configuration
1205         */
1206        public void configure(String name, String filePath) {
1207            long start = System.currentTimeMillis();
1208            if (filePath == null) {
1209                return;
1210            }
1211            loggerConf.info("configuring aspect " + name + " with file "+filePath); 
1212            List configMethods = null;
1213            try {
1214                // Naming.PARSER_NAME ("parserimpl#0") is the only
1215                // instance of ACParser, if we are on the master site, it
1216                // is automatically instantiated by the binding aspect, if
1217                // not, the binding aspect creates a stub for
1218                // parserimpl#0@mastersite
1219                Parser acp = (Parser)NameRepository.get().getObject(Naming.PARSER_NAME);
1220                configMethods = acp.parse(filePath,this.getClass().getName(),
1221                                          this.getBlockKeywords());
1222            } catch (FileNotFoundException e) {
1223                logger.warn("cannot find config file "+filePath+" for "+name+
1224                            "("+e+"), using serialized infos.");
1225            } catch (Exception e) {
1226                logger.error("configure "+name+","+filePath,e);
1227                return;
1228            }
1229            if (configMethods==null)
1230                return;
1231            currentImports = new Imports();
1232            for (int i=0; i<configMethods.size(); i++) {
1233                MethodItem method = null;
1234                Object statement = configMethods.get(i);
1235                if (statement instanceof ImportStatement) {
1236                    ImportStatement imp = (ImportStatement)statement;
1237                    currentImports.add(imp.getExpr());
1238                    continue;
1239                }
1240                ConfigMethod cm = (ConfigMethod)statement;
1241                currentConfigMethod = cm;
1242                if (cm==null) {
1243                    loggerConf.warn("skipping error");
1244                    continue;
1245                }
1246                try {
1247                    loggerConf.debug(
1248                        "invoking configuration method '"+cm.getMethod()+
1249                        "' on "+this.getClass()+" with "+Arrays.asList(cm.getArgs()));
1250                    if (cm.getMethod().equals("")) 
1251                        continue;
1252                    MethodItem[] methodItems =
1253                        cr.getClass(this.getClass()).
1254                        getMethods(cm.getMethod());
1255                    if (methodItems==null || methodItems.length==0) {
1256                        loggerConf.warn("No such configuration method "+cm.getMethod()+
1257                                        " in AC "+this.getClass());
1258                    }
1259                    loggerConf.debug(
1260                        "matching methods : "+Arrays.asList(methodItems));
1261    
1262                    Object[] paramValues = null;
1263                    //determine which method to call based on number of parameters
1264                    // Warning, ClassItem+String can become a MemberItem
1265                    Vector exceptions = new Vector();
1266                    for(int j=0; j<methodItems.length && method==null; j++) {
1267                        paramValues = cm.getArgs();
1268                        //If the ConfigMethod has the same number of param as MethodItem
1269                        if (methodItems[j].getParameterTypes().length==paramValues.length) {
1270                            method = methodItems[j];
1271                            loggerConf.debug("selecting method "+method);
1272    
1273                            // Try to convert the parameters
1274                            // if it fails, try the next method
1275                            paramValues = cm.getArgs();
1276                            try {
1277                                Class[] paramTypes = method.getParameterTypes();
1278                                for(int k=0; k<paramTypes.length; k++) {
1279                                    paramValues[k] = 
1280                                        ACConfiguration.convertValue(
1281                                            paramValues[k], 
1282                                            paramTypes[k], 
1283                                            currentImports);
1284                                }
1285                                break;
1286                            } catch(Exception e) {
1287                                exceptions.add(e);
1288                                method = null;
1289                            }
1290                        }
1291                        //If method==null try to translate MemberItem parameters
1292                        //into ClassItem+String
1293                        if (method==null && 
1294                            (methodItems[j].getParameterCount()>0)) {
1295                            for (int p=0; p<methodItems[j].getParameterCount(); p++) {
1296                                if ((MemberItem.class.isAssignableFrom(
1297                                    methodItems[j].getParameterTypes()[p])) 
1298                                    && (methodItems[j].getParameterTypes().length
1299                                        == paramValues.length-1)) 
1300                                {
1301                                    method = methodItems[j];
1302                                    loggerConf.debug(
1303                                        "selecting method "+method+
1304                                        " with MemberItem=ClassItem+String for param #"+p);
1305                                    paramValues = cm.getArgs();
1306                                    Object paramValuesTranslated[] = new Object[paramValues.length-1];
1307                                    try {
1308                                        Class[] paramTypes = method.getParameterTypes();
1309                                        ClassItem classItem = 
1310                                            (ClassItem)ACConfiguration.convertValue(
1311                                                paramValues[p],
1312                                                ClassItem.class, 
1313                                                currentImports);
1314                                        paramValuesTranslated[p] =
1315                                            classItem.getMember(
1316                                                (String)ACConfiguration.convertValue(
1317                                                    paramValues[p+1],
1318                                                    String.class,
1319                                                    currentImports));
1320                                        if (!paramTypes[p].isAssignableFrom(
1321                                                paramValuesTranslated[p].getClass())) 
1322                                        {
1323                                            throw new Exception(
1324                                                "Error translating parameter: "+
1325                                                paramValuesTranslated[0].getClass().getName()+
1326                                                " can't be assigned to "+paramTypes[p].getName());
1327                                        }
1328                                        for(int k=p+1; k<paramTypes.length; k++){
1329                                            paramValuesTranslated[k] = 
1330                                                ACConfiguration.convertValue(
1331                                                    paramValues[k+1], 
1332                                                    paramTypes[k],
1333                                                    currentImports);
1334                                        }
1335    
1336                                        for(int k=0; k<p; k++){
1337                                            paramValuesTranslated[k] = 
1338                                                ACConfiguration.convertValue(
1339                                                    paramValues[k], 
1340                                                    paramTypes[k],
1341                                                    currentImports);
1342                                        }
1343                                        paramValues = paramValuesTranslated;
1344                                        loggerConf.debug("Parameter transformation successful");
1345                                        break;
1346                                    } catch (Exception e) {
1347                                        loggerConf.debug("Exception in parameter transformation: "+e);
1348                                        exceptions.add(e);
1349                                        method = null;
1350                                    }
1351                                }
1352                            }
1353                        }
1354                   
1355                    }
1356                    if (method == null) {
1357                        if (exceptions.isEmpty()) {
1358                            throw new Exception("Wrong number of parameters for method "+
1359                                                cm.getMethod());
1360                        } else {
1361                            throw (Exception)exceptions.get(0);
1362                            //new Exception(exceptions.toString());
1363                        }
1364                    }
1365                
1366                    loggerConf.debug(
1367                        filePath+": line "+cm.getLineNumber() +
1368                        ", invoke configuration method '" + 
1369                        (method!=null?method.toString():cm.getMethod()) +
1370                        "' on " +  this.getClass() + 
1371                        " with " + Arrays.asList(cm.getArgs()));
1372                    method.invoke(this,paramValues);
1373    
1374                } catch (InvocationTargetException e) {
1375                    Throwable target = e.getTargetException();
1376                    loggerConf.warn(cm.getLineNumber() +
1377                                    ", failed to invoke configuration method '"+
1378                                    (method!=null?method.toString():cm.getMethod())+
1379                                    "' on "+this.getClass() + " with "+
1380                                    Arrays.asList(cm.getArgs()),target);
1381                    loggerConf.info("Stack trace follows",e);
1382                } catch (Throwable e) {
1383                    loggerConf.warn(cm.getLineNumber() +
1384                                    ", failed to invoke configuration method '"+ 
1385                                    (method!=null?method.toString():cm.getMethod())+
1386                                    "' on "+this.getClass()+
1387                                    " with "+Arrays.asList(cm.getArgs())+" : "+e);
1388                    loggerConf.info("Stack trace follows",e);
1389                } finally {
1390                    currentConfigMethod = null;
1391                }
1392            }
1393            loggerPerf.debug(
1394                "aspect configuration file "+filePath+" read in "+
1395                (System.currentTimeMillis()-start)+"ms");
1396        }
1397    
1398        public void beforeWrappeeInit(Wrappee wrappee) {};
1399    
1400        public void afterWrappeeInit(Wrappee wrappee) {};
1401    
1402        /**
1403         * Issue a warning containing the file, line number and
1404         * configuration method name (if available)
1405         *
1406         * @param message the warning message to print 
1407         * @see #error(String)
1408         */
1409        protected void warning(String message) {
1410            if (currentConfigMethod!=null)
1411                loggerConf.warn(
1412                    currentConfigMethod.getLineNumber()+":"+
1413                    currentConfigMethod.getMethod()+": "+message);
1414            else
1415                loggerConf.warn(message);
1416        }
1417    
1418        /**
1419         * Issue an error containing the file, line number and
1420         * configuration method name (if available)
1421         *
1422         * @param message the warning message to print 
1423         * @see #warning(String)
1424         */
1425        protected void error(String message) {
1426            if (currentConfigMethod!=null)
1427                loggerConf.error(
1428                    currentConfigMethod.getLineNumber()+":"+
1429                    currentConfigMethod.getMethod()+": "+message);
1430            else
1431                logger.error(message);
1432        }
1433    
1434        /**
1435         * Returns a named aspect component in the same application
1436         */
1437        protected AspectComponent getAC(String name) {
1438            return ACManager.getACM().getACFromFullName(application+"."+name);
1439        }
1440    }