001    /*
002      Copyright (C) 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.HashMap;
022    import java.util.Iterator;
023    import java.util.Map;
024    import org.apache.log4j.Logger;
025    import org.objectweb.jac.core.ACManager;
026    
027    /**
028     * This class is the root class for the composite aspect components
029     * defined by JAC aspect programmers.
030     *
031     * <p>A composite aspect is a kind of facade that factorizes and
032     * simplifies the use of a set of sub-aspects (called chidren
033     * aspects). For instance, the user and authentication aspects of JAC
034     * can be factorized in on unique aspect in order to simplify the use
035     * (factorization) and to eliminate useless dependencies.
036     *
037     * @author <a href="mailto:renaud@aopsys.com">Renaud Pawlak</a> */
038    
039    public class CompositeAspectComponent extends AspectComponent {
040        static Logger logger = Logger.getLogger("aspects.composite");
041    
042        Map childClasses=new HashMap();
043        Map children=new HashMap();
044        Map defaultConfigs=new HashMap();
045    
046        /**
047         * The default constructor.
048         *
049         * <p>Should be redefined be the programmer in order to declare the child aspects.
050         *
051         * @see #addChild(String,Class) */
052        public CompositeAspectComponent () {   
053            super();
054        }
055    
056        /**
057         * Invoke this method in the constructor in order to disable the
058         * application of the default configuration for a given child
059         * aspect component.
060         * 
061         * <p>Note that the default configs are defined by the
062         * <code>getDefaultConfig</code> method. By default, all the
063         * children's default configs are applied. */
064        protected void disableDefaultConfigs(String childName) {
065            defaultConfigs.put(childName,Boolean.FALSE);
066        }
067    
068        /**
069         * Declares a new child for this composite (should be invoked from
070         * the constructor).
071         *
072         * @param name the child's name (can be any unique id)
073         * @param acClass the aspect component's class of the child */
074        protected void addChild(String name,Class acClass) {
075            logger.debug("addChild("+name+
076                      ","+acClass+")"+" to composite "+getName());
077            childClasses.put(name,acClass);
078        }
079    
080        /**
081         * Removes a child for this composite (do not use unless you know
082         * what you are doing).
083         *
084         * @param name the child's name as given in the {@link
085         * #addChild(String,Class)} method */
086        protected void removeChild(String name) { 
087            logger.debug("removeChild("+name+
088                      ") from composite "+getName()+")");
089            childClasses.remove(name); }
090    
091        /**
092         * Returns a child aspect component from its name.
093         *
094         * <p>This method should be used in configuration methods of the
095         * composite to delegate the configuration to the child
096         * aspects. */
097        protected AspectComponent getChild(String name) {
098            logger.debug("getChild("+name+
099                      ") in composite "+getName());
100            return (AspectComponent)children.get(name);
101        }
102    
103        /**
104         * Returns the internal name of a child (applicationName.name).
105         *
106         * @param name the child's name */ 
107        protected String getChildActualName(String name) {
108            logger.debug("getChildActualName("+name+
109                      ") in composite "+getName());
110            return getChild(name).getApplication()+"."+name;
111        }
112    
113        /**
114         * Returns the internal name of a child, as it is registered in
115         * the JAC ACManager.
116         *
117         * <p>Note that this method will return null if the child is not
118         * yet registered in the AC manager. This is the case at
119         * configuration time. Thus, {@link #getChildActualName(String)}
120         * should be prefered.
121         *
122         * @param name the child's name */ 
123        protected String getChildRegisteredName(String name) {
124            logger.debug("getChildActualName("+name+
125                      ") in composite "+getName());
126            return ACManager.getACM().getName(getChild(name));
127        }
128    
129        /**
130         * This method is upcalled by the system when the composite aspect
131         * is about to be configured.
132         *
133         * <p>This method instantiates all the declared children (with
134         * {@link #addChild(String,Class)} method. */
135        public void beforeConfiguration() throws Exception {
136            logger.debug("beforeConfiguration()"+
137                      " for composite "+getName());
138            Iterator it=childClasses.entrySet().iterator();
139            while(it.hasNext()) {
140                Map.Entry entry=(Map.Entry)it.next();
141                Class acClass=(Class)entry.getValue();
142                AspectComponent instance = (AspectComponent) acClass.newInstance();
143                instance.setApplication(getApplication());
144                children.put(entry.getKey(),instance);
145                // apply the default configurations if needed
146                String[] defaults = instance.getDefaultConfigs();
147                for (int i=0; i<defaults.length; i++) {
148                    instance.configure((String)entry.getKey(),defaults[i]);
149                }
150            }
151    
152        }
153    
154        /**
155         * This method is upcalled by the system when the composite aspect
156         * is actually registered in the AC manager.
157         *
158         * <p>It symply registers all the children with the right
159         * names. */
160        public final void doRegister() {
161            logger.debug("registerChildren()"+
162                         " for composite "+getName());
163            Iterator it=children.entrySet().iterator();
164            while(it.hasNext()) {
165                Map.Entry entry=(Map.Entry)it.next();
166                AspectComponent ac=(AspectComponent)entry.getValue();
167                ACManager.get().register( ac.getApplication() + 
168                                          "." + entry.getKey(), ac );
169            }       
170            logger.debug("end registerChildren() => ACM dump: "+
171                         ACManager.get().getPrintableString());
172    
173        }
174    
175    
176        /**
177         * This method is upcalled by the system when the composite aspect
178         * is actually unregistered in the AC manager.
179         *
180         * <p>It symply unregisters all the children. */
181        public final void doUnregister() {
182            logger.debug("unregisterChildren()"+
183                         " for composite "+getName());
184            Iterator it=children.entrySet().iterator();
185            while(it.hasNext()) {
186                Map.Entry entry=(Map.Entry)it.next();
187                AspectComponent ac=(AspectComponent)entry.getValue();
188                ACManager.get().unregister( ac.getApplication() + 
189                                            "." + entry.getKey() );
190            }       
191        }
192    
193    }