001    /*
002      Copyright (C) 2001 Renaud Pawlak, Laurent Martelli, Lionel
003      Seinturier, Fabrice Legond-Aubry.
004    
005      This program is free software; you can redistribute it and/or modify
006      it under the terms of the GNU Lesser General Public License as
007      published by the Free Software Foundation; either version 2 of the
008      License, or (at your option) any later version.
009    
010      This program is distributed in the hope that it will be useful,
011      but WITHOUT ANY WARRANTY; without even the implied warranty of
012      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013      GNU Lesser General Public License for more details.
014    
015      You should have received a copy of the GNU Lesser General Public
016      License along with this program; if not, write to the Free Software
017      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
018      USA */
019    
020    package org.objectweb.jac.core;
021    
022    import gnu.regexp.RE;
023    import gnu.regexp.REException;
024    import java.util.*;
025    import org.apache.log4j.Logger;
026    import org.objectweb.jac.util.Strings;
027    
028    /**
029     * This class is used to load all the properties necessary to the
030     * execution of JAC. This class is called by the <code>Jac</code>,
031     * <code>JacLoader</code> and <code>JacObject</code> and
032     * <code>CompositionAspect</code> classes.
033     *
034     * @see JacLoader
035     * @see Jac
036     * @author Renaud Pawlak
037     * @author Lionel Seinturier
038     * @author Laurent Martelli */
039    
040    public abstract class JacPropLoader extends JacPropTools {
041        static Logger logger = Logger.getLogger("props");
042    
043        /**************************************************************
044         * Static members.
045         **************************************************************/
046    
047        /** The JAC property file name. */
048        public final static String propFileName = "jac.prop";
049        
050        /** The name of the property in the the jac.prop file. */
051        public final static String toNotAdaptProp = "jac.toNotAdapt";
052        
053        /** The name of the property in the the jac.prop file. */
054        public final static String toAdaptProp = "jac.toAdapt";
055    
056        /** The name of the property in the the jac.prop file. */
057        public final static String wrappableMethodsProp = "jac.wrappableMethods";
058    
059        /** property name for classes whose fields must not be translated */
060        public final static String dontTranslateFieldsProp = "jac.dontTranslateField";
061        
062        /** The name of the property in the the jac.prop file. */
063        public final static String toWrapProp = "jac.toWrap";
064            
065            /** The name of the property that defines the initial global
066                    topology in the jac.prop file. */
067        public final static String topologyProp = "jac.topology";
068           
069        /**
070         * The jac.prop property string to declare initially woven aspect
071         * components. */
072        public final static String acsProp = "jac.acs";
073        
074        /**
075         * The jac.prop property string to declare when the initially woven
076         * aspect components are woven. */
077        public final static String startWeavingPlacesProp = "jac.startWeavingPlaces";
078        
079        /**
080         * The jac.prop property string to set the composition aspect class
081         * name. */
082        public final static String compositionAspectProp = "jac.comp.compositionAspect";
083        
084    
085        /** The name of the wrapping order property in the prop file. */
086        public final static String wrappingOrderProp = "jac.comp.wrappingOrder";
087    
088        /** The name of the incompatible property in the prop file. */
089        public final static String incompatibleACsProp = "jac.comp.imcompatibleACs";
090    
091        /** The name of the dependent property in the prop file. */
092        public final static String dependentACsProp = "jac.comp.dependentACs";
093    
094        /** The name of the property in the the jac.prop file. */
095        public final static String bytecodeModifierProp = "jac.bytecodeModifier";
096    
097        /** Property key for the remote reference class. */
098        public static final String remRefClassProp = "jac.remoteRefClass";
099            
100        /** Default remote reference class. */
101        public static final String remRefDefaultClassName = "org.objectweb.jac.core.dist.rmi.RMIRemoteRef";
102    
103        /** Property key for the class providing a naming service. */
104        public static final String namingClassProp = "org.objectweb.jac.core.dist.namingClass";
105    
106        /** Default class providing a naming service. */
107        public static final String namingClassDefaultName = "org.objectweb.jac.core.dist.rmi.RMINaming";
108    
109        /** The properties loaded from the jac.prop file. */
110        public static Properties props = new Properties();
111       
112        /** Store the packages (set of classes) translated to be
113            wrappable. */
114        public static HashSet packagesToAdapt = new HashSet();
115       
116        /** Store the packages (set of classes) translated to be not
117            wrappable. */
118        public static HashSet packagesToNotAdapt = new HashSet();
119    
120        /** Store the methods that are wrappable (per class) */
121        public static Hashtable wrappableMethods = new Hashtable();
122    
123        /** Store the classes whose fields must not be translated */
124        public static HashSet dontTranslateFields = new HashSet();
125       
126        public static HashSet packagesToWrap = new HashSet();
127       
128        public static String compositionAspect = null;
129       
130        /** The name of the bytecode modifier package */
131        public static String bytecodeModifier = null;
132       
133        public static String remoteRefClassName = null;
134       
135        public static String namingClassName = null;
136       
137        /** Stores all the declared aspect components. */
138        public static Hashtable declaredACs = new Hashtable();
139       
140        /** Store the default wrapping order. */
141        public static  Vector wrappingOrder = new Vector();
142       
143        /** Store the exclusive aspect component pairs. */
144        public static  Vector incompatibleACs = new Vector();
145       
146        /** Store the dependent aspect component pairs. */
147        public static Vector dependentACs = new Vector();
148       
149        public static int acs_count=0;
150    
151        static HashSet packagesToAdaptRE = new HashSet();
152    
153        static HashSet packagesToNotAdaptRE = new HashSet();
154    
155        /**
156         * Add some properties.
157         * @param ps the properties to add
158         * @return true is ps!=null, false otherwise
159         */
160        public static boolean addProps(Properties ps) {
161            String tmp;
162            if (ps==null)
163                return false;
164            for (Enumeration e = ps.propertyNames() ; e.hasMoreElements() ;) {
165                String key=(String)e.nextElement();
166                String value=ps.getProperty(key);
167                if (value!=null)
168                    props.setProperty(key,value);
169            }
170    
171            // Get list of packages that must not be adpated
172            fillSetProps(packagesToNotAdapt, ps, toNotAdaptProp, false);
173            Iterator i = packagesToNotAdapt.iterator();
174            packagesToNotAdaptRE.clear();
175            while (i.hasNext()) {
176                String pkg = (String)i.next();
177                try {
178                    packagesToNotAdaptRE.add(new RE("^"+Strings.replace(Strings.replace(Strings.replace(pkg,"$","\\$"),".","\\."),"*",".*")+"$"));
179                } catch(REException e) {
180                    logger.warn("RE exception: "+e);
181                }
182            }
183          
184            // Get list of packages that must be adpated
185            fillSetProps(packagesToAdapt, ps, toAdaptProp, false);
186            i = packagesToAdapt.iterator();
187            packagesToAdaptRE.clear();
188            while (i.hasNext()) {
189                String pkg = (String)i.next();
190                try {
191                    packagesToAdaptRE.add(new RE("^"+Strings.replace(Strings.replace(Strings.replace(pkg,"$","\\$"),".","\\."),"*",".*")+"$"));
192                } catch(REException e) {
193                    logger.warn("RE exception: "+e);
194                }
195            }
196          
197            // Get list of packages that must be wrapped
198            fillSetProps(packagesToWrap, ps, toWrapProp, true);
199          
200            // Get list of methods that must be wrappable
201            fillMapProps(wrappableMethods, ps, wrappableMethodsProp, 0, false);
202    
203            // Get classes whose collection fields must not be translated
204            fillSetProps(dontTranslateFields,ps,dontTranslateFieldsProp,false);
205    
206            // Get list of aspects that must be weaved
207            fillMapProps(declaredACs, ps, acsProp, 1, false);
208          
209            // Get the order of aspects wrapping 
210            fillListStringProps(wrappingOrder, ps, wrappingOrderProp, false);
211          
212            fillListStringProps(dependentACs, ps, dependentACsProp, false);
213          
214            fillListStringProps(incompatibleACs, ps, incompatibleACsProp, false);
215          
216            tmp=fillStringProp(ps, compositionAspectProp);
217            if (tmp!=null) compositionAspect = tmp;
218          
219          
220            //Get the bytecode modifier name
221            tmp= fillStringProp (ps, bytecodeModifierProp);
222            if (tmp!=null) bytecodeModifier = tmp;
223          
224          
225            //Get the 
226            tmp= fillStringProp (ps, remRefClassProp);
227            if (tmp!=null) bytecodeModifier = tmp;
228          
229            //Get the 
230            tmp= fillStringProp (ps, namingClassProp);
231            if (tmp!=null) bytecodeModifier = tmp;
232          
233            return true;
234        }
235    
236        public static void loadProps(boolean d) {
237            loadProps();
238        }
239    
240        /**
241         * Try to load the properties and set all the internal hash tables
242         * in order to be used by the JAC core objects. No parameters. No
243         * returns.
244         */
245        public static void loadProps() {
246            boolean propsInMemory = false;
247            //props = new Properties();
248          
249            // FOR TEST PURPOSE ONLY
250            /*
251              String myr=System.getProperty ("JAC_ROOT","vide");
252              Properties p=System.getProperties();
253              String elt;
254              for (Enumeration e = p.propertyNames() ; e.hasMoreElements() ;) {
255              elt=(String)e.nextElement();
256              System.out.println ("key '"+ elt + "' has value "+p.getProperty(elt));
257            
258              }
259            */
260          
261            // Try to read a jac.prop in JAC_ROOT
262            //System.getProperty("user.dir");
263            //File f = new File(".");
264            //loadDirectory = f.getAbsolutePath();
265            if (!Strings.isEmpty(Jac.getJacRoot()))
266                propsInMemory |= addProps(getPropsFrom(Jac.getJacRoot(), propFileName));
267          
268            String directory;
269            directory = System.getProperty("JAC_ROOT",null);
270            if (directory != null)
271                propsInMemory |= addProps(getPropsFrom(directory, propFileName));
272          
273          
274            // Try to read a jac.prop in $HOME
275            directory = System.getProperty("user.home",null);
276            if  (directory!=null)
277                propsInMemory|=addProps(getPropsFrom(directory, propFileName));
278          
279            // Try to read a jac.prop file from the current directory       
280            propsInMemory |= addProps(getPropsFrom("./", propFileName));
281          
282            //Stop everything if not, at least, one jac property file is found 
283            //Call System.exit();
284            if (!propsInMemory)
285            {
286                logger.warn("Can not find the '"+propFileName+"' file.");
287            }
288          
289            acs_count=declaredACs.size();
290            if (bytecodeModifier == null)
291                bytecodeModifier = "BCEL";
292          
293            if (remoteRefClassName == null)
294                remoteRefClassName = remRefDefaultClassName;
295          
296            if (namingClassName == null)
297                namingClassName = namingClassDefaultName;
298        }
299    
300        /**
301         * Returns true if the fields of the specified class must be translated
302         */
303        public static boolean translateFields(String className) {
304            Iterator i = dontTranslateFields.iterator();
305            while (i.hasNext()) {
306                try {
307                    RE dontTranslate = new RE((String)i.next());
308                    logger.debug("Testing "+dontTranslate);
309                    if (dontTranslate.isMatch(className)) {
310                        logger.debug("Do not translate fields for "+className);
311                        return false;
312                    }
313                } catch (REException e) {
314                    logger.warn("RE exception: "+e);
315                }
316            }
317            logger.debug("Translate fields for "+className);
318            return true;
319        }
320    
321        /**
322         * Returns true if the specified class matches the toAdapt property.
323         */
324        public static boolean adaptClass(String className) {
325            logger.debug("Adapt class "+className+" ???");
326            Iterator i = packagesToAdaptRE.iterator();
327            while (i.hasNext()) {
328                RE regexp = (RE)i.next();
329                logger.debug("Testing "+regexp);
330                if (regexp.isMatch(className)) {
331                    logger.debug("Adapt "+className);
332                    return true;
333                }
334            }
335            logger.debug("Do not force adaptation of "+className);
336            return false;
337        }
338    
339        /**
340         * Returns true if the specified class matches the toNotAdapt property.
341         */
342        public static boolean doNotAdaptClass(String className) {
343            logger.debug("Do not adapt class "+className+" ???");
344            Iterator i = packagesToNotAdaptRE.iterator();
345            while (i.hasNext()) {
346                RE regexp = (RE)i.next();
347                logger.debug("Testing "+regexp);
348                if (regexp.isMatch(className)) {
349                    logger.debug("Do not adapt "+className);
350                    return true;
351                }
352            }
353            logger.debug("Adaptation not disabled for "+className);
354            return false;
355        }
356    }