001    /*
002      Copyright (C) 2001-2002 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.FileInputStream;
022    import java.io.IOException;
023    import java.io.InputStream;
024    import java.io.StreamTokenizer;
025    import java.io.StringReader;
026    import java.lang.NoSuchMethodException;
027    import java.lang.reflect.InvocationTargetException;
028    import java.lang.reflect.Method;
029    import java.lang.reflect.Modifier;
030    import java.net.URLClassLoader;
031    import java.util.Arrays;
032    import java.util.HashMap;
033    import java.util.Hashtable;
034    import java.util.Properties;
035    import java.util.StringTokenizer;
036    import org.apache.log4j.Logger;
037    import org.objectweb.jac.core.rtti.*;
038    import org.objectweb.jac.util.*;
039    
040    /**
041     * This class is a repository for all the applications defined in the
042     * JAC system.
043     *
044     * @see Application */
045    
046    public class ApplicationRepository {
047        static Logger logger = Logger.getLogger("jac");
048        static Logger loggerCP = Logger.getLogger("classpath");
049        static Logger loggerAspects = Logger.getLogger("aspects");
050    
051        static Hashtable owningApplications = new Hashtable();
052       
053        public static Application getOwningApplication(Wrappee wrappee,
054                                                       ClassItem cl) {
055            if (wrappee!=null)
056                return (Application)owningApplications.get(wrappee);
057            else if (cl!=null)
058                return (Application)owningApplications.get(cl);
059            else
060                return null;
061        }
062    
063        public static String getOwningApplicationName(Wrappee wrappee,
064                                                      ClassItem cl) {
065            Application app = getOwningApplication(wrappee,cl);
066            if (app!=null)
067                return app.getName();
068            else
069                return null;
070        }
071       
072        public static void setOwningApplication(Wrappee wrappee,ClassItem cl,
073                                                Application application) {
074            if(wrappee!=null)
075                owningApplications.put(wrappee,application);
076            else if(cl!=null)
077                owningApplications.put(cl,application);
078        }
079    
080        HashMap applications = new HashMap();
081    
082        static ApplicationRepository applicationRepository;
083    
084        /**
085         * Returns the application of the current thread.
086         *
087         * @return an application, null if none */
088    
089        public static Application getCurrentApplication() {
090            String appName = (String)Collaboration.get().getCurApp();
091            if( appName == null ) return null;
092            return (Application)get().applications.get(appName);
093        }
094    
095        /**
096         * Launches a JAC program.
097         *
098         * @param args the program arguments (first is the .jac file) */
099    
100        public static void launchProgram(String [] args) {
101            InputStream fis = null;
102            Properties applicationDescriptor = new Properties();
103          
104            try {
105                fis = new FileInputStream(args[0]);
106                applicationDescriptor.load(fis);
107            } catch(Exception e) {
108                ClassLoader loader = ApplicationRepository.class.getClassLoader();
109                    
110                loggerCP.debug("trying to load "+args[0]+" with "+loader);
111                fis = loader.getResourceAsStream(args[0]);
112                if (fis == null) {
113                    logger.error("cannot find application descriptor "+args[0]);
114                    if (loader instanceof URLClassLoader)
115                        logger.error("  classpath="+Arrays.asList(((URLClassLoader)loader).getURLs()));
116                    return;
117                }
118                try {
119                    applicationDescriptor.load(fis);
120                } catch (IOException ioe) {
121                    logger.error("failed to read applicationDescriptor descriptor "+
122                                 args[0]+": "+ioe);
123                    return;
124                }
125            }
126    
127            // We must use reflection here because
128            // JacLoader.class!=ApplicationRepository.class.getClassLoader().class
129            ClassLoader loader = ApplicationRepository.class.getClassLoader();
130            try {
131                loader.getClass().getMethod("readProperties",
132                                            new Class[] {Properties.class})
133                    .invoke(loader,new Object[] {applicationDescriptor});
134            } catch (Exception e) {
135                logger.error("failed to read JAC properties from application descriptor "+args[0]);
136            }
137    
138            JacPropLoader.addProps(applicationDescriptor);
139    
140            String applicationName = 
141                applicationDescriptor.getProperty("applicationName");
142            String launchingClass = 
143                applicationDescriptor.getProperty("launchingClass");
144            String aspects = applicationDescriptor.getProperty("aspects");
145            String topology = applicationDescriptor.getProperty("topology");
146    
147            if (applicationName==null) {
148                logger.warn("bad application descriptor "+args[0]);
149                return;
150            }
151          
152            logger.info("launching application "+applicationName);
153    
154            // bind to the given topology if any
155            if (topology!=null) {
156                Class remoteContainerClass = null;
157                try {
158                    remoteContainerClass = 
159                        Class.forName("org.objectweb.jac.core.dist.RemoteContainer");
160                } catch (ClassNotFoundException e) {
161                    logger.fatal("Could not find class org.objectweb.jac.core.dist.RemoteContainer");
162                    System.exit(1);
163                }
164                StringTokenizer st1 = new StringTokenizer(topology);
165                while (st1.hasMoreElements()) {
166                    String container = (String)st1.nextElement();
167                    try {
168                        remoteContainerClass.getMethod("bindNewContainer",
169                                                       new Class[] {String.class})
170                            .invoke(null,new Object[] {container});
171                    } catch (InvocationTargetException e) {
172                        logger.error("Failed to bind to "+container+": "+
173                                     e.getTargetException().getMessage());
174                    } catch (Exception e) {
175                        logger.error("Failed to bind to "+container+": "+e.getMessage());
176                    }
177                }
178                logger.debug("application topology successfully bound");
179            }
180    
181            // create the application
182            Application app = new Application(applicationName,null,
183                                              launchingClass,null);
184          
185            // create the aspects configurations
186            if (aspects!=null) {
187                StreamTokenizer tokens = 
188                    new StreamTokenizer(new StringReader(aspects));
189                tokens.wordChars('/','/');
190                tokens.wordChars('_','_');
191                tokens.wordChars('-','-');
192                tokens.wordChars(':',':');
193                tokens.wordChars('$','$');
194                char fileSep = System.getProperty("file.separator").charAt(0);
195                tokens.wordChars(fileSep,fileSep);
196                try {
197                    while (tokens.nextToken()!=StreamTokenizer.TT_EOF) {
198                        String ac_name = tokens.sval;
199                        tokens.nextToken();
200                        String ac_path = tokens.sval;
201                        tokens.nextToken();
202                        String ac_weave = tokens.sval;
203                        loggerAspects.info(
204                            "adding aspect "+ac_name+"["+ac_path+
205                            "]:"+ac_weave+" to "+app);
206                        app.addAcConfiguration( 
207                            new ACConfiguration(app, ac_name, 
208                                                ac_path, 
209                                                (ac_weave.equals("true")?true:false)));
210                    }
211                } catch (IOException e) {
212                    e.printStackTrace();
213                }
214            }
215          
216            logger.debug("adding application "+app);
217            ApplicationRepository.get().addApplication(app);
218          
219            try {
220                String[] appargs = new String[args.length - 1];
221                if (appargs.length > 0) {
222                    System.arraycopy(args, 1, appargs, 0, args.length - 1);
223                }
224                Class lc = Class.forName(launchingClass);
225                try {
226                    Method mainMethod = lc.getMethod("main",new Class[] {String[].class});
227                    if (!Modifier.isStatic(mainMethod.getModifiers())) {
228                        logger.error("main method of class "+launchingClass+" is not static");
229                        return;
230                    }
231                    mainMethod.invoke(null,new Object[] {appargs});
232                } catch (NoSuchMethodException e) {
233                    logger.error("No such method "+launchingClass+".main(String[])");
234                    return;
235                }
236            } catch(Exception e) {
237                logger.error(applicationName+" launch failed",e);
238            }
239            ((ACManager)ACManager.get()).afterApplicationStarted();
240        }
241    
242        /**
243         * Launches and initializes the application repository (this method
244         * is called by the system).
245         *
246         * @param args the launching arguments of JAC */
247    
248        public static void main(String[] args) throws Throwable {
249            if (applicationRepository == null) 
250                applicationRepository = new ApplicationRepository();
251            launchProgram(args);
252        }
253    
254        public ApplicationRepository() {
255        }
256    
257        /**
258         * Gets the sole instance of the application repository within the
259         * local JAC system.
260         *
261         * @return the application repository */
262    
263        public static ApplicationRepository get() {
264            if (applicationRepository == null) {
265                applicationRepository = new ApplicationRepository();
266            }
267            return applicationRepository;
268        }
269    
270        /**
271         * Adds an application within the repository.
272         *
273         * <p>When added, the application is initialized so that the needed
274         * aspects are woven.
275         *
276         * @param app the application to add */
277    
278        public void addApplication(Application app) {
279            logger.info("--- Launching " +app+ " ---"); 
280            applications.put(app.getName(), app);
281            app.init();
282        }
283    
284        /**
285         * Returns the applications that have been added to the repository.
286         *
287         * @return a hash map (application's name -> application)
288         * @see #addApplication */
289     
290        public HashMap getApplications() {
291            return applications;
292        }
293    
294        /**
295         * Gets an application from its name.
296         *
297         * @param name the application's name
298         * @return the application named <code>name</code>
299         * @see #getApplications() */
300       
301        public Application getApplication(String name) {
302            return (Application) applications.get(name);
303        }
304    
305        /**
306         * Extends an application with a given aspect (only if this
307         * application has a configuration for this aspect and if this
308         * aspect is not yet woven).
309         *
310         * @param applicationName the application's name
311         * @param aspectName the aspect's name */
312    
313        public void extend(String applicationName, String aspectName) {
314            if (ACManager.get().getObject(applicationName+"."+aspectName)!=null)
315                return;
316            loggerAspects.info("extending application "+applicationName+
317                               " with "+aspectName);
318            Application application = getApplication(applicationName);
319            if (application == null) {
320                logger.error("No such application to extend: "+applicationName);
321            }
322            ACConfiguration acConf = application.getAcConfiguration(aspectName);
323            if (acConf == null) {
324                logger.error("No such AC configuration: "+aspectName+
325                             " found in "+applicationName);
326            }
327            acConf.weave();
328        }
329    
330        /**
331         * Un-extends an application with a given aspect (only if this
332         * application has a configuration for this aspect and if this
333         * aspect is woven).
334         *
335         * @param applicationName the application's name
336         * @param aspectName the aspect's name */
337    
338        public void unextend(String applicationName, String aspectName) {
339            loggerAspects.info("un-extending application "+applicationName+
340                               " with "+aspectName);
341            Application application = getApplication(applicationName);
342            if (application == null) {
343                logger.error("No such application to extend: "+applicationName);
344            }
345            ACConfiguration acConf = application.getAcConfiguration(aspectName);
346            if (acConf == null) {
347                logger.error("No such AC configuration: "+aspectName+
348                             " found in "+applicationName);
349            }
350            acConf.unweave();
351        }
352    
353    }