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 License
015      along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
017    
018    package org.objectweb.jac.aspects.naming;
019    
020    import java.util.Hashtable;
021    import java.util.Map;
022    import org.apache.log4j.Logger;
023    import org.objectweb.jac.core.*;
024    import org.objectweb.jac.core.Interaction;
025    import org.objectweb.jac.core.rtti.ClassItem;
026    import org.objectweb.jac.util.ExtArrays;
027    import org.objectweb.jac.util.Log;
028    
029    /**
030     * @author <a href="http://cedric.cnam.fr/~pawlak/index-english.html">Renaud Pawlak</a>
031     */
032    
033    /**
034     * Handles the naming aspect within the JAC system.
035     *
036     * <p>This aspect component automatically registers all the created
037     * JAC object into the sole instance of <code>NameRepository</code>.
038     *
039     * @see NameRepository */
040    
041    public class NamingAC extends AspectComponent {
042    
043        static Logger logger = Logger.getLogger("naming");
044        static Logger loggerSerial = Logger.getLogger("serialization");
045    
046        /**
047         * Creates a naming aspect component.
048         *
049         * <p>It creates the name repository if it does not exist yet.
050         *
051         * @see NameRepository 
052         */
053        public NamingAC() {
054    
055            setSystemListener(true);
056    
057            NameRepository nr = (NameRepository) NameRepository.get();
058            if (nr == null) {
059                System.out.println ("Error: cannot create name repository.");
060                System.exit(-1);
061            }
062        }
063    
064        NameGenerator nameGen = new NameGenerator();
065    
066        /**
067         * Name a new instance using the <code>nameObject()</code> and
068         * <code>generateName()</code> methods.
069         *
070         * @see #nameObject(Object,String)
071         * @see NameGenerator#generateName(String) 
072         */
073        public void whenUsingNewInstance(Interaction interaction) {
074            //if (interaction.wrappee.getClass().getName().startsWith("org.objectweb.jac.lib.java.util.")) {
075            // do nothing for collections
076            //   return;
077            //}
078            if (interaction.wrappee==null) {
079                // do nothing for static methods
080                return;
081            }
082            logger.debug("when using new instance "+interaction.wrappee.getClass());
083            if (NameRepository.get().getName(interaction.wrappee)!=null) {
084                return;
085            }
086            if ( !(interaction.wrappee instanceof AspectComponent) ) {
087                nameObject(interaction.wrappee, (String)attr(Naming.FORCE_NAME));
088                attrdef(Naming.FORCE_NAME, null);
089            }
090            //System.out.println( "EO Naming " + interaction.wrappee );      
091        }
092    
093        /**
094         * This method is upcalled when a new object is instanciated from a
095         * remote site.
096         * 
097         * <p>The name that is passed is the name of the remote reference
098         * that has been used to create the object. Thus, the default
099         * behavior of the naming aspect is to register the new object into
100         * the name repository.
101         * 
102         * @param newInstance the remotly created new instance
103         * @param name the name that was forwarded from the creator host
104         * 
105         * @see NameRepository
106         * @see org.objectweb.jac.util.Repository#register(String,Object) */
107    
108        public void whenRemoteInstantiation(Wrappee newInstance, String name) {
109            logger.debug("whenRemoteInstantiation "+newInstance+","+name);
110            NameRepository.get().register(name, newInstance);
111        }
112    
113        /**
114         * Name a single object by registering it in the name repository
115         * (see the <code>NameRepository</code> class).
116         * 
117         * <p>If the repository does not exist, it is created.
118         *
119         * @param object the object to name
120         * @param name the given name
121         * @return the new name of the object
122         *
123         * @see NameRepository
124         * @see org.objectweb.jac.util.Repository#register(String,Object) 
125         */
126        public String nameObject(Object object, String name) {
127            NameRepository nr = (NameRepository)NameRepository.get();
128            if (nr==null) {
129                logger.error("Error: cannot create name repository.");
130                throw new RuntimeException("Error: cannot create name repository.");
131            }
132            if (name == null) {
133                name = nameGen.generateName(object.getClass().getName());
134                logger.debug("generated name "+object+" -> "+name);
135                name = ACManager.getACM().whenNameObject(object,name);
136            } else {
137                logger.debug("forced name "+object+" -> "+name);
138            }
139            logger.debug("Registering "+object+" -> "+name);
140            nr.register(name, object);
141            return name;
142        }
143    
144        /**
145         * Returns the counters used to generate unique names
146         */
147        public Map getNameCounters() {
148            Hashtable counters = new Hashtable();
149            counters.putAll(nameGen);
150            ((ACManager)ACManager.get()).getNameCounters(counters);
151            return counters;
152        }
153    
154        public void updateNameCounters(Map counters) {
155            nameGen.update(counters);
156        }
157    
158        /**
159         * Add the name to the <code>SerializedJacObject</code> structure
160         * when serialized.
161         *
162         * <p>This allows the name to be serialized with a JAC object so
163         * that the object can be named with the same name when deserialized
164         * (see <code>BindingAC</code>).
165         *
166         * @param finalObject the structure corresponding to the object
167         * that is being serialized
168         *
169         * @see BindingAC#whenDeserialized(SerializedJacObject,Wrappee)
170         * @see org.objectweb.jac.core.SerializedJacObject#setACInfos(String,Object)
171         */
172    
173        public Wrappee whenSerialized(Wrappee orgObject, 
174                                      SerializedJacObject finalObject) {
175    
176            if(orgObject.getClass().getName().startsWith("org.objectweb.jac.lib.java.util")) {
177                return orgObject;
178            }
179    
180            NameRepository nr = (NameRepository) NameRepository.get();
181            String name = nr.getName(orgObject);
182            if (name!=null) {
183                loggerSerial.debug("NAMING: serializing object " + name );
184                finalObject.setACInfos(ACManager.get().getName(this), name);
185            } else {
186                if (Wrapping.isExtendedBy(orgObject,null,
187                                          org.objectweb.jac.wrappers.ForwardingWrapper.class)) {
188                    loggerSerial.debug("NAMING: Serializing forwardee for " + orgObject );
189                    Object newOrg = Wrapping.invokeRoleMethod(orgObject,
190                                                              "getForwardee",
191                                                              ExtArrays.emptyObjectArray);
192                    if (newOrg!=null) {
193                        orgObject = (Wrappee)newOrg;
194                    } else {
195                        logger.warn("Oooops!! Forwardee is " + newOrg);
196                    }
197                }
198                name = nr.getName(orgObject);
199                if (name!=null) {
200                    loggerSerial.debug("NAMING: serializing object " + name +" (PASS 2)");
201                    finalObject.setACInfos(ACManager.get().getName(this), name);
202                } else {
203                    logger.warn("Oooops!! Object is still unamed: "+orgObject);
204                    //System.out.println( "NAMING: still a forwarder? => " + orgObject.isExtendedBy( jac.wrappers.ForwarderWrapper.class) );
205                }
206            }
207            return orgObject;
208        }
209    }