001    /*
002      Copyright (C) 2001-2003 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.util.*;
022    import org.apache.log4j.Logger;
023    import org.objectweb.jac.core.rtti.*;
024    import org.objectweb.jac.util.*;
025    
026    /**
027     * @author <a href="mailto:pawlak@cnam.fr">Renaud Pawlak</a>
028     */
029    
030    /**
031     * This class manages all the aspect components that are present in
032     * the JAC system.
033     *
034     * <p>When a new aspect component is registered, it is
035     * woven regarding its weaving properties. Once woven, the aspect
036     * component manager dispatches all the events of the
037     * <code>BaseProgramListener</code> to it.
038     *
039     * @see AspectComponent
040     * @see BaseProgramListener */
041    
042    public class ACManager extends OrderedRepository 
043       implements BaseProgramListener 
044    {
045        static Logger logger = Logger.getLogger("jac");
046        static Logger loggerAspects = Logger.getLogger("aspects");
047        static Logger loggerACM = Logger.getLogger("acm");
048        static Logger loggerWuni = Logger.getLogger("wuni");
049    
050        /**
051        * A internally-used flag to bootstrap the AC manager. */
052    
053        public boolean registering = false;
054    
055        /**
056        * Get the sole instance of Aspect Component Manager for this
057        * JAC container.
058        * 
059        * <p>If this instance does not exist yet, then it is created.
060        *
061        * <p>This method returns a <code>Repository</code> so that the
062        * result must be casted to used specific method of
063        * <code>ACManager</code>.
064        *
065        * @return the aspect component manager of the local container
066        * @see org.objectweb.jac.util.Repository */
067       
068        public static Repository get() {
069            if ( acManager == null ) {
070                acManager = new ACManager();
071            }
072            return acManager;
073        }
074    
075        public static ACManager getACM() {
076            return acManager;
077        }
078    
079        public AspectComponent[] getAspectComponents() {
080            return (AspectComponent[])objects.values().toArray(new AspectComponent[0]);
081        }
082    
083        /** Stores the sole instance of Aspect Component Manager. */
084        protected static ACManager acManager = null;
085    
086        /** Stores all the declared aspect components. */
087        protected Hashtable declaredACs = (Hashtable) JacPropLoader.declaredACs;
088    
089        static {
090            Runtime.getRuntime().addShutdownHook(
091                new Thread() {
092                        public void run() {
093                            if (acManager!=null) {
094                                logger.info("JAC system shutdown: notifying all ACs...");
095                                acManager.onExit();
096                            }
097                            logger.info("Bye bye.");
098                        }
099                    }
100            );
101            //GarbageCollector.init();
102        }
103    
104        /**
105        * Declares a new aspect component.
106        *
107        * @param name the name of the aspect component
108        * @param path its path (must be accessible from the current
109        * classpath) */
110    
111        public void declareAC(String name, String path) { 
112            loggerAspects.debug("declaring "+path+" as "+name);
113            declaredACs.put(name, path);
114        }
115    
116        public boolean isACDeclared(String name) {
117            if (name==null) return false;
118            return (declaredACs.get(name) != null);
119        }
120    
121        /**
122        * Gets a declared aspect component path from its name.
123        *
124        * @param acName the name of the AC
125        * @return the corresponding path, null if not declared */
126    
127        public String getACPathFromName(String acName) {
128            return (String)declaredACs.get(acName);
129        }
130    
131        /**
132        * Gets the declared aspect components.
133        *
134        * @return the set of the declared aspect components names */
135    
136        public Set getDeclaredACs() {
137            return declaredACs.keySet();
138        }
139    
140        /**
141        * Registers a declared aspect as is (not linked to an application
142        * and with no configuration).
143        *
144        * @param name the aspect name */
145    
146        public AspectComponent registerDeclaredAC(String name) {
147            AspectComponent ac = null;
148            try {
149                if ( !acManager.isRegistered(name) ) {
150                    String className = getACPathFromName(name);
151                    loggerAspects.debug("registering the "+name+" ac");
152                    acManager.register(
153                        name, ac = (AspectComponent) Class.forName(className).newInstance());
154                } else {
155                    loggerAspects.debug(name+" is already registered");
156                }            
157            } catch (Exception e) {
158                e.printStackTrace();
159            }
160            return ac;
161        }
162    
163        /**
164         * Called by the JAC launcher to create and declare the aspect components
165         * defined in jac.prop. */
166    
167        public static void main(String[] args) throws Throwable {
168    
169            ACManager acManager = (ACManager)get();
170    
171            loggerAspects.debug("initializing the AC manager");
172    
173            try {
174    
175                // Create the Composition Aspect 
176                //String prop1 = JacObject.props.getProperty(compositionAspectProp);
177                AspectComponent ac = null;
178                try {
179                    loggerAspects.debug("compositionAspect = "+
180                               JacPropLoader.compositionAspect);
181                    loggerAspects.debug("JacPropLoader = "+
182                               Strings.hex(JacPropLoader.class));
183                    JacPropLoader.loadProps();
184                    ac = (AspectComponent) Class.forName(
185                        JacPropLoader.compositionAspect ).newInstance();
186                } catch (Exception e) {
187                    e.printStackTrace();
188                    System.exit(1);
189                }
190                acManager.register("JAC_composition_aspect", ac);
191    
192                /** Creating the needed aspects. */
193                
194                acManager.registerDeclaredAC("naming");
195                acManager.registerDeclaredAC("binding");
196                acManager.registerDeclaredAC("rtti");
197                //         acManager.registerDeclaredAC( "deployment" );
198    
199            } catch (Exception e) {
200                e.printStackTrace();
201            }
202                  
203        }
204    
205        /**
206         * Returns an AC of a given name for the current application.
207         * @param name aspect's name
208         */
209        public AspectComponent getAC(String name) {
210            String appName = Collaboration.get().getCurApp();
211            if (appName==null) {
212                loggerAspects.error("getAC("+name+") cannot work because curApp==null");
213            }
214            return (AspectComponent)getObject(appName+"."+name);
215        }
216    
217        /**
218        * Returns an AC of a given name
219        * @param fullName aspect's full name (<application_name>.<aspect_name>)
220        */
221        public AspectComponent getACFromFullName(String fullName) {
222            return (AspectComponent)getObject(fullName);
223        }
224    
225        /**
226        * The default constructor will set the acManager field to the
227        * right value and bind the JAC internal MOP to it so that it will
228        * be notified of the base program events.
229        *
230        * @see BaseProgramListener */
231    
232        public ACManager () {
233        }
234    
235        /**
236        * Dispatch this event to all the registered Aspect Components.
237        *
238        * @param newInstance the remotly created instance
239        * @param name the original remote name 
240        * @see AspectComponent#whenRemoteInstantiation(Wrappee,String)
241        * @see BaseProgramListener#whenRemoteInstantiation(Wrappee,String) */
242    
243        public final void whenRemoteInstantiation(Wrappee newInstance, 
244                                                  String name) {
245            System.out.println("------ REMINST "+name+"-> "+newInstance);
246            Iterator it = orderedObjects.iterator();
247            while (it.hasNext()) {
248                AspectComponent curac = (AspectComponent)it.next();
249                curac.whenRemoteInstantiation(newInstance, name);
250            }
251        }
252    
253        /**
254        * Dispatch this event to all the registered Aspect Components that
255        * are woven.
256        * 
257        * @see AspectComponent#whenUsingNewInstance(Interaction)
258        * @see BaseProgramListener#whenUsingNewInstance(Interaction) 
259        */
260    
261        public final void whenUsingNewInstance(Interaction interaction) {
262            loggerWuni.debug("whenUsingNewInstance "+Strings.hex(interaction.wrappee));
263            //      Collaboration collab = Collaboration.get();
264            //      String old_ac = (String)collab.getCurAC();
265            try {
266                ClassItem cli = interaction.getClassItem();
267                boolean isJacClass = cli.getName().startsWith("org.objectweb.jac.core");
268                Vector toNotify = (Vector)orderedObjects.clone();
269                for (int i=0; i<toNotify.size(); i++) { 
270                    AspectComponent curac = (AspectComponent)toNotify.get(i);
271                    loggerAspects.debug("curac = "+names.get(curac));
272                    //            collab.setCurAC((String)names.get(curac));
273                    if ((!isJacClass) || curac.isSystemListener()) {
274                        loggerWuni.debug("  wuni "+curac.getName());
275                        curac.whenUsingNewInstance(interaction);
276                    }
277                }
278            } catch (Exception e) {
279                loggerWuni.error("ACManager.whenUsingNewInstance "+interaction,e);
280             
281            } /*
282                finally {
283                collab.setCurAC(old_ac);
284                }
285              */
286        }
287    
288        HashSet initializedClasses = new HashSet();
289        public final synchronized void whenUsingNewClass(ClassItem cl) {
290            if (!initializedClasses.contains(cl)) {
291                loggerAspects.debug("whenUsingNewClass "+cl);
292                try {
293                    Vector toNotify = (Vector)orderedObjects.clone();
294                    for (int i=0; i<toNotify.size(); i++) { 
295                        AspectComponent curac = (AspectComponent)toNotify.get(i);
296                        loggerAspects.debug("curac = "+names.get(curac));
297                        curac.whenUsingNewClass(cl);
298                    }
299                } catch ( Exception e ) {
300                    e.printStackTrace();
301                }
302                initializedClasses.add(cl);
303            }
304        }
305    
306        /**
307        * Dispatch this event to all the woven Aspect Components.
308        *
309        * <p>Note: the current collaboration contains an attribute called
310        * "orgObject" and that is a reference to the object that is
311        * currently serialized.
312        *
313        * @param finalObject the corresponding serialized structure.
314        * @see AspectComponent#whenSerialized(Wrappee,SerializedJacObject)
315        * @see BaseProgramListener#whenSerialized(Wrappee,SerializedJacObject)
316        */
317    
318        public final Wrappee whenSerialized(Wrappee orgObject, 
319                                            SerializedJacObject finalObject) {
320            Iterator it = orderedObjects.iterator();
321            while (it.hasNext()) {
322                AspectComponent curac = (AspectComponent)it.next();
323                orgObject = curac.whenSerialized(orgObject,finalObject);
324            }
325            return orgObject;
326        }
327    
328        /**
329        * Dispatch this event to all the woven Aspect Components.
330        *
331        * <p>Note: the current collaboration contains an attribute called
332        * "finalObject" and that is a reference to the object that is
333        * will be finally deserialized.
334        *
335        * @param orgObject the corresponding serialized structure.
336        * @see AspectComponent#whenDeserialized(SerializedJacObject,Wrappee)
337        * @see BaseProgramListener#whenDeserialized(SerializedJacObject,Wrappee) 
338        */
339    
340        public final Wrappee whenDeserialized(SerializedJacObject orgObject,
341                                              Wrappee finalObject) {
342            Iterator it = orderedObjects.iterator();
343            while (it.hasNext()) {
344                AspectComponent curac = (AspectComponent)it.next();
345                finalObject = curac.whenDeserialized(orgObject,finalObject);
346            }
347            return finalObject;
348        }
349    
350        /** 
351        * Apply all the woven aspect components to the given wrappee.
352        *
353        * @param wrappee the wrappee that have to be treated
354        */
355    
356        public final void simulateUsingNewInstance(Wrappee wrappee) {
357            if (wrappee==null) 
358                return;
359    
360            Iterator it=((Vector)orderedObjects.clone()).iterator();
361            while(it.hasNext()) {
362                AspectComponent curac = (AspectComponent)it.next();
363                curac.simulateUsingNewInstance(wrappee);
364            }
365        }
366    
367        /**
368        * Dispatch this event to all the registered Aspect Components that
369        * are woven.
370        * 
371        * @param cloned the wrappee that is being cloned
372        * @param clone the new clone of cloned
373        * @see AspectComponent#whenClone(Wrappee,Wrappee)
374        * @see BaseProgramListener#whenClone(Wrappee,Wrappee) */
375    
376        public final void whenClone(Wrappee cloned, Wrappee clone) {
377            Object[] acs = orderedObjects.toArray();
378            for ( int i=0; i<acs.length; i++) {
379                AspectComponent curac = (AspectComponent)acs[i];
380                curac.whenClone(cloned, clone);
381            }
382        }
383    
384        public final void whenDeleted(Wrappee object) {
385            Object[] acs = orderedObjects.toArray();
386            for (int i=0; i<acs.length; i++) {
387                AspectComponent curac = (AspectComponent)acs[i];
388                curac.whenDeleted(object);
389            }
390        }
391    
392        public final void whenFree(Wrappee object) {
393            Object[] acs = orderedObjects.toArray();
394            for (int i=0; i<acs.length; i++) {
395                AspectComponent curac = (AspectComponent)acs[i];
396                curac.whenFree(object);
397            }
398        }
399    
400        /**
401        * Dispatch this event to all the registered Aspect Components that
402        * are woven.
403        * 
404        * @see AspectComponent#afterApplicationStarted() */
405    
406        public final void afterApplicationStarted() {
407            Object[] acs = orderedObjects.toArray();
408            for ( int i = 0; i < acs.length; i++ ) {
409                AspectComponent curac = (AspectComponent)acs[i];
410                curac.afterApplicationStarted();
411            }
412        }
413    
414        public final void onExit() {
415            Object[] acs = orderedObjects.toArray();
416            for ( int i = 0; i < acs.length; i++ ) {
417                AspectComponent curac = (AspectComponent)acs[i];
418                curac.onExit();
419            }
420        }
421    
422    
423        /**
424        * Dispatch this event to all the registered Aspect Components that
425        * are woven.
426        * 
427        * @see AspectComponent#whenTopologyChanged() */
428    
429        public final void whenTopologyChanged() {
430            Object[] acs = orderedObjects.toArray();
431            for ( int i = 0; i < acs.length; i++ ) {
432                AspectComponent curac = (AspectComponent)acs[i];
433                curac.whenTopologyChanged();
434            }
435        }
436       
437        /**
438        * Dispatch this event to all the registered Aspect Components that
439        * are woven.
440        * 
441        * @see AspectComponent#whenCloseDisplay(Display) */
442    
443        public final void whenCloseDisplay(Display display) {
444            Object[] acs = orderedObjects.toArray();
445            for ( int i = 0; i < acs.length; i++ ) {
446                AspectComponent curac = (AspectComponent)acs[i];
447                curac.whenCloseDisplay(display);
448            }
449        }
450    
451        /**
452        * Forward this event to the aspect component that owns the
453        * wrapper.
454        *
455        * @param wrapper the wrapper that is going to be runned
456        * @param wrappingMethod the name of the may-be runned wrapping
457        * @see AspectComponent#beforeRunningWrapper(Wrapper,String)
458        * @see BaseProgramListener#beforeRunningWrapper(Wrapper,String) */
459    
460        public final boolean beforeRunningWrapper(Wrapper wrapper,
461                                                  String wrappingMethod) {
462            boolean ret = true;
463            AspectComponent ac = wrapper.getAspectComponent();      
464          
465            if (ac != null) {
466                if (!ac.beforeRunningWrapper(wrapper,wrappingMethod)) {
467                    ret = false;
468                }
469            }
470            return ret;
471        }
472    
473        /**
474        * Upcall the beforeRunningWrapper method of all the aspect
475        * component that owns the wrapper.
476        *
477        * @param wrapper the wrapper that has just been runned
478        * @param wrappingMethod the name of the runned wrapping method
479        * @see AspectComponent#afterRunningWrapper(Wrapper,String)
480        * @see BaseProgramListener#afterRunningWrapper(Wrapper,String) */
481    
482        public final void afterRunningWrapper(Wrapper wrapper,
483                                              String wrappingMethod) {
484            AspectComponent ac = wrapper.getAspectComponent();
485            if (ac != null) {
486                ac.afterRunningWrapper(wrapper, wrappingMethod);
487            }
488        }
489    
490        /**
491        * Upcall the beforeRunningWrapper method of all the aspect
492        * component that owns the wrapper.
493        *
494        * @see AspectComponent#afterWrap(Wrappee,Wrapper,String[],String[][]) */
495    
496        public final void afterWrap(Wrappee wrappee, Wrapper wrapper, 
497                                    String[] wrapping_methods, 
498                                    String[][] wrapped_methods) {
499            Object[] acs = orderedObjects.toArray();
500            for (int i=0; i<acs.length; i++) {
501                AspectComponent curac = (AspectComponent)acs[i];
502                curac.afterWrap(wrappee, wrapper, wrapping_methods, wrapped_methods);
503            }
504        }
505    
506        public void whenGetObjects(Collection objects, ClassItem cl)
507        {
508            Iterator it = orderedObjects.iterator();
509            while (it.hasNext()) {
510                AspectComponent curac = (AspectComponent)it.next();
511                try {
512                    curac.whenGetObjects(objects,cl);
513                } catch (Exception e) {
514                    loggerAspects.error("whenGetObjects failed on "+curac,e);
515                }
516            }
517        }
518    
519        public String whenNameObject(Object object, String name)
520        {
521            Iterator it = orderedObjects.iterator();
522            while (it.hasNext()) {
523                AspectComponent curac = (AspectComponent)it.next();
524                name = curac.whenNameObject(object,name);
525            }
526            return name;
527        }
528    
529        public void getNameCounters(Map counters) {
530            Iterator it = orderedObjects.iterator();
531            while (it.hasNext()) {
532                AspectComponent curac = (AspectComponent)it.next();
533                curac.getNameCounters(counters);
534            }
535        }
536    
537        /**
538         * Update name counters 
539         */
540        public void updateNameCounters(Map counters) {
541            Iterator it = orderedObjects.iterator();
542            while (it.hasNext()) {
543                AspectComponent curac = (AspectComponent)it.next();
544                curac.updateNameCounters(counters);
545            }
546        }
547    
548        public void whenObjectMiss(String name)
549        {
550            loggerACM.debug("whenObjectMiss("+name+")");
551            Iterator it = orderedObjects.iterator();
552            while (it.hasNext()) {
553                AspectComponent curac = (AspectComponent)it.next();
554                logger.debug("whenObjectMiss("+curac+")");
555                curac.whenObjectMiss (name);
556            }
557        }
558    
559        /**
560        * Register a new aspect component.
561        *
562        * <p>When a new aspect component is registered, the
563        * <code>allWoven</code> flag is set to false. And the
564        * <code>checkWeaving</code> method will be called for each base
565        * method call until all the aspect components are woven.
566        *
567        * @param name the aspect component key for the AC manager
568        * @param aspectComponent the registered aspect component 
569        * @see AspectComponent#weave()
570        */
571    
572        public final boolean register(String name, Object aspectComponent) {
573            loggerAspects.debug("registering AC "+name);
574            Object o = names.get(name);
575            if (o != null) {
576                // reject if already registered
577                return false;
578            }
579            //registering = true;
580            AspectComponent ac = (AspectComponent) aspectComponent;
581            //ac.init();
582          
583            //AspectComponent compAC = (AspectComponent) names.get( 
584            //   "JAC_composition_aspect" );
585          
586            boolean ret = super.register(name, ac);
587    
588            loggerAspects.debug("memory objects = "+ObjectRepository.getMemoryObjects());
589            Iterator it = ObjectRepository.getMemoryObjects().iterator();
590            while( it.hasNext() ) {
591                Wrappee cur = (Wrappee) it.next();
592                String className = cur.getClass().getName();
593                if ( ! ( className.equals("org.objectweb.jac.core.NameRepository") ||
594                         className.equals("org.objectweb.jac.core.ACManager") || 
595                         className.equals("org.objectweb.jac.core.dist.Topology") ) ) {
596                    if ( (! className.startsWith("org.objectweb.jac.core")) || ac.isSystemListener() ) {
597                        loggerAspects.debug("simulateUsingNewInstance on "+cur.getClass());
598                        ac.simulateUsingNewInstance(cur);
599                    }
600                }
601            }
602            //nonWovenACs.add ( ac );
603            //allWoven = false;
604            //registering = false;
605            return ret;
606        }
607    
608        /**
609        * A resister method that can be used by a UI.
610        *
611        * <p>This method creates a new aspect component with the name of
612        * the given class and registers it. It will be woven immediatly.
613        *
614        * @param name the aspect component key for the AC manager
615        * @param className the aspect component class name
616        * @see ACManager#register(String,Object)
617        * @see AspectComponent#weave() */
618    
619        public final boolean registerWithName(String name, String className) {
620            boolean ret = false;
621            try {
622                ret = register(name, Class.forName(className).newInstance());
623            } catch (Exception e) {
624                e.printStackTrace();
625            }
626            return ret;
627        }
628    
629        /**
630        * Register (if not allready registered) and weaves a new Aspect
631        * Component.
632        *
633        * @param ac the aspect component to weave
634        * @see ACManager#register(String,Object)
635        * @see AspectComponent#weave() */
636    
637        public final void weave(AspectComponent ac) {
638            if (names.get(ac) == null) {
639                register(ac.toString(),ac);
640            }
641        }   
642    
643        /**
644        * Unregister a given aspect component (it is then unwoven). 
645        *
646        * @param name the aspect component key for the AC manager
647        * @see #register(String,Object)
648        * @see AspectComponent#unweave() */
649       
650        public final void unregister(String name) {
651            AspectComponent ac = (AspectComponent)objects.get(name);
652            if (ac == null) {
653                loggerAspects.debug("'"+name+"' aspect component not found. ("+names+")");
654                return;
655            }
656            ac.unweave();
657            super.unregister(name);
658        }
659    
660        // following methods implement the CollaborationParticipant interface
661    
662        public final void attrdef( String name, Object value ) {
663            Collaboration.get().addAttribute( name, value );
664        }
665        
666        public final Object attr(String name) {
667            return Collaboration.get().getAttribute(name);
668        }
669    
670        /**
671        * Reload an aspect for an application
672        * @param application the application's name
673        * @param aspect the aspect's name
674        */
675        public void reloadAspect(String application, String aspect) {
676            String fullName = application+"."+aspect;
677            logger.info("Reloading "+fullName); 
678            AspectComponent ac = getACFromFullName(fullName);
679            if (ac != null) {
680                ApplicationRepository.get().unextend(application,aspect);
681                ac.beforeReload();
682                ApplicationRepository.get().extend(application,aspect);
683                ac.whenReload();
684            }
685        }
686    
687        /**
688        * Reload an aspect for the current application
689        * @param aspect the aspect's name
690        */
691        public void reloadAspect(String aspect) throws Exception {
692            String application = Collaboration.get().getCurApp();
693            if (application==null) {
694                throw new Exception("No current application in context");
695            }
696            reloadAspect(application,aspect);
697        }
698    
699          /*
700       public static Collection getWeavedAspects() {
701          String application = Collaboration.get().getCurApp();
702          if (application==null) {
703             throw new Exception("No current application in context");
704          }
705          AspectComponent[] aspects = getACM().getAspectComponents();
706          Vector weavedAspects = new Vector(aspects.length);
707          for (int i=0; i<aspects.length; i++) {
708             if (application.equals(aspects[i].getApplication())
709                 && aspects[i].)
710          }
711          return weavedAspects;
712       }
713          */
714    
715        public final void beforeWrappeeInit(Wrappee wrappee) {
716            Object[] acs = orderedObjects.toArray();
717            for (int i = 0; i < acs.length; i++) {
718                AspectComponent curac = (AspectComponent)acs[i];
719                curac.beforeWrappeeInit(wrappee);
720            }
721        }
722    
723        public final void afterWrappeeInit(Wrappee wrappee) {
724            Object[] acs = orderedObjects.toArray();
725            for (int i = 0; i < acs.length; i++) {
726                AspectComponent curac = (AspectComponent)acs[i];
727                curac.afterWrappeeInit(wrappee);
728            }
729        }
730    
731    }