001    /*
002      Copyright (C) 2002-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.ide;
020    
021    import java.io.FilenameFilter;
022    import java.io.IOException;
023    import java.util.Arrays;
024    import java.util.Collection;
025    import java.util.HashSet;
026    import java.util.Hashtable;
027    import java.util.Iterator;
028    import java.util.LinkedList;
029    import java.util.List;
030    import java.util.Map;
031    import java.util.Set;
032    import java.util.Vector;
033    import org.apache.log4j.Level;
034    import org.objectweb.jac.core.Jac;
035    import org.objectweb.jac.util.File;
036    import org.objectweb.jac.util.Pipe;
037    import org.objectweb.jac.util.Strings;
038    
039    public class Application extends ModelElement {
040    
041        public Application() {
042        }
043    
044        Vector hosts = new Vector();
045       
046        /**
047         * Get the value of hosts.
048         * @return value of hosts.
049         */
050        public List getHosts() {
051            return hosts;
052        }
053       
054        public void addHost(String host) {
055            hosts.add(host);
056        }
057    
058        public void removeHost(String host) {
059            hosts.remove(host);
060        }
061    
062        String name;
063       
064        /**
065         * Get the value of name.
066         * @return value of name.
067         */
068        public String getName() {
069            return name;
070        }
071       
072        /**
073         * Set the value of name.
074         * @param v  Value to assign to name.
075         */
076        public void setName(String  v) {
077            this.name = v;
078        }
079    
080        Class mainClass;
081       
082        /**
083         * Get the value of mainClass.
084         * @return value of mainClass.
085         */
086        public Class getMainClass() {
087            return mainClass;
088        }
089       
090        /**
091         * Set the value of mainClass.
092         * @param v  Value to assign to mainClass.
093         */
094        public void setMainClass(Class  v) {
095            this.mainClass = v;
096        }
097       
098        Vector aspectConfigurations = new Vector();
099       
100        /**
101         * Get the value of aspectConfigurations.
102         * @return value of aspectConfigurations.
103         */
104        public List getAspectConfigurations() {
105            return aspectConfigurations;
106        }
107       
108        public void addAspectConfiguration(AspectConfiguration a) {
109            aspectConfigurations.add(a);
110        }
111    
112        public void removeAspectConfiguration(AspectConfiguration a) {
113            aspectConfigurations.remove(a);
114        }
115    
116        Vector externalPaths = new Vector();
117        /**
118         * Get the value of externalPaths.
119         * @return value of externalPaths.
120         */
121        public List getExternalPaths() {
122            return externalPaths;
123        }
124        public void addExternalPath(String path) {
125            externalPaths.add(path);
126        }
127        public void removeExternalPath(String path) {
128            externalPaths.remove(path);
129        }
130    
131        /**
132         * Classes that JAC must not translate
133         */
134        Set ignoredClasses = new HashSet();
135        public Set getIgnoredClasses() {
136            return ignoredClasses;
137        }
138        public void addIgnoredClass(String expr) {
139            ignoredClasses.add(expr);
140        }
141        public void removeIgnoredClass(String expr) {
142            ignoredClasses.remove(expr);
143        }
144    
145        Project project;
146        /**
147         * Get the value of project.
148         * @return value of project.
149         */
150        public Project getProject() {
151            return project;
152        }
153        /**
154         * Set the value of project.
155         * @param v  Value to assign to project.
156         */
157        public void setProject(Project  v) {
158            this.project = v;
159        }
160    
161        boolean startSwingGUI = false;
162        public void setStartSwingGUI(boolean value) {
163            this.startSwingGUI = value;
164        }
165        public boolean getStartSwingGUI() {
166            return startSwingGUI;
167        }
168    
169        String swingGUIs;
170        public String getSwingGUIs() {
171            return swingGUIs;
172        }
173        public void setSwingGUIs(String  v) {
174            this.swingGUIs = v;
175        }
176       
177        String webGUIs;
178        public String getWebGUIs() {
179            return webGUIs;
180        }
181        public void setWebGUIs(String  v) {
182            this.webGUIs = v;
183        }
184       
185        boolean startWebGUI = false;
186        public void setStartWebGUI(boolean value) {
187            this.startWebGUI = value;
188        }
189        public boolean getStartWebGUI() {
190            return startWebGUI;
191        }
192    
193        boolean enableDistribution = true;
194        public void setEnableDistribution(boolean value) {
195            this.enableDistribution = value;
196        }
197        public boolean isDistributionEnabled() {
198            return enableDistribution;
199        }
200    
201        String serverName = "s1";
202        public void setServerName(String name) {
203            this.serverName = name;
204        }
205        public String getServerName() {
206            return serverName;
207        }
208       
209        String otherOptions = "";
210        public String getOtherOption() {
211            return otherOptions;
212        }
213        public void setOtherOptions(String options) {
214            this.otherOptions = options;
215        }
216    
217        String jvmOptions = "";
218        public String getJvmOption() {
219            return jvmOptions;
220        }
221        public void setJvmOptions(String options) {
222            this.jvmOptions = options;
223        }
224    
225        Map properties = new Hashtable();
226        public Map getProperties() {
227            return properties;
228        }
229        public void addProperty(String name, String value) {
230            properties.put(name,value);
231        }
232        public void removeProperty(String name) {
233            properties.remove(name);
234        }
235    
236        boolean enableDebugging;
237        public boolean isEnableDebugging() {
238            return enableDebugging;
239        }
240        public void setEnableDebugging(boolean enableDebugging) {
241            this.enableDebugging = enableDebugging;
242        }
243    
244        int debugPort = 4444;
245        public int getDebugPort() {
246            return debugPort;
247        }
248        public void setDebugPort(int debugPort) {
249            this.debugPort = debugPort;
250        }
251    
252        transient Process currentProcess = null;
253        public void resetCurrentProcess() {
254            currentProcess = null;
255        }
256    
257        public boolean isStarted() {
258            return currentProcess!=null;
259        }
260        public boolean isNotStarted() {
261            return currentProcess==null;
262        }
263    
264        public File getJacFile() {
265            return new File(
266                new File(project.getGenerationPath(),getGenerationName()),
267                getGenerationName()+".jac");
268        }
269    
270        /**
271         * Returns the command and arguments to run the application
272         */
273        public String[] getRunCommandAndArgs() {
274            File dir = new File(project.getGenerationPath(),name);
275            Vector runCmd = new Vector();
276            runCmd.add("java");
277    
278            runCmd.addAll(Strings.splitToList(jvmOptions," "));
279    
280            if (enableDebugging) {
281                runCmd.add("-Xdebug");
282                runCmd.add("-Xrunjdwp:transport=dt_socket,address="+debugPort+",server=y,suspend=n");
283            }
284    
285            runCmd.add("-Djava.security.policy="+
286                       org.objectweb.jac.core.Jac.getJacRoot()+"jac.policy");
287    
288            // So that is works on MacOS X
289            runCmd.add("-Dswing.defaultlaf=javax.swing.plaf.metal.MetalLookAndFeel");
290    
291            File jar = new File(org.objectweb.jac.core.Jac.getJacRoot()+"jac.jar");
292            String jacroot = org.objectweb.jac.core.Jac.getJacRoot();
293            String sep = System.getProperty("path.separator");
294    
295            // add the classpath defined in the project and all jars in $JAC_ROOT/lib
296            List classpath = new LinkedList(getProject().getClasspath());
297            File libDir = new File(jacroot,"lib");
298            classpath.add(new File(jacroot,"classes"));
299            classpath.add(new File(jacroot,"src"));
300            if (jar.exists())
301                classpath.add(jar);
302            classpath.addAll(
303                libDir.listFilesRecursively(
304                    new FilenameFilter() {
305                            public boolean accept(java.io.File file, String name) {
306                                return name.endsWith(".jar");
307                            }
308                        }
309                ));
310            if (classpath.size()>0) {
311                runCmd.add("-classpath");
312                runCmd.add(Strings.join(classpath,sep));
313            }
314    
315            Iterator it = properties.entrySet().iterator();
316            while (it.hasNext()) {
317                Map.Entry entry = (Map.Entry)it.next();
318                runCmd.add("-D"+entry.getKey()+"="+entry.getValue());
319            }
320    
321            runCmd.add("org.objectweb.jac.core.Jac");
322             
323            runCmd.add("-w");
324            if (enableDistribution) {
325                runCmd.add("-D");
326                if (serverName!=null && !serverName.equals(""))
327                    runCmd.add(serverName);
328            }
329    
330            if (!Strings.isEmpty(jacroot)) {
331                runCmd.add("-R");
332                runCmd.add(jacroot);
333            }
334            runCmd.add("-C");
335            runCmd.add(project.getGenerationPath().getPath()+
336                       sep+new File(project.getGenerationPath(),"classes").getPath()+
337                       sep+project.getClasspathString());
338    
339            String msg="Starting application '"+name+"'";
340            if (startSwingGUI) {
341                runCmd.add("-G");
342                runCmd.add(swingGUIs);
343                msg = msg+" (Swing GUIs: "+swingGUIs+")";
344            }
345    
346            if (startWebGUI) {
347                runCmd.add("-W");
348                runCmd.add(webGUIs);
349                msg = msg+" (Web GUIs: "+webGUIs+")";
350            }
351    
352            runCmd.addAll(Strings.splitToList(otherOptions," "));
353    
354            runCmd.add(new File(dir,name+".jac").getPath());
355    
356            return (String[])runCmd.toArray(new String[] {});
357        }
358    
359        public void start() throws IOException {
360            if (!startSwingGUI && !startWebGUI) {
361                throw new RuntimeException(
362                    "You should probably start a GUI (see \"Run options\""+
363                    " of the application)");
364            }
365    
366            if (isStarted()) {
367                stop();
368            }
369    
370            String msg="Starting application '"+name+"'";
371            if (startSwingGUI) {
372                msg = msg+" (Swing GUIs: "+swingGUIs+")";
373            }
374            if (startWebGUI) {
375                msg = msg+" (Web GUIs: "+webGUIs+")";
376            }
377            org.objectweb.jac.aspects.gui.Actions.showStatus(msg);
378    
379            String[] runCmd = getRunCommandAndArgs();
380            //Log.trace("ide.run",0,"Run command = "+Arrays.asList(runCmd));
381            currentProcess = Runtime.getRuntime().exec(runCmd);
382    
383            Pipe outputPipe = new Pipe(currentProcess.getInputStream(),System.out);
384            outputPipe.start();
385            Pipe errorPipe = new Pipe(currentProcess.getErrorStream(),System.out);
386            errorPipe.start();
387            new Thread() {
388                    public void run() {
389                        while (currentProcess!=null) {
390                            try {
391                                currentProcess.waitFor();
392                                //Log.trace("ide","Current process completed");
393                                resetCurrentProcess();
394                            } catch (InterruptedException e) {
395                                //Log.trace("ide","Exception while waiting for "+currentProcess);
396                            }
397                        }
398                    }
399                }.start();
400        }
401    
402        public void stop() {
403            if (currentProcess!=null) {
404                currentProcess.destroy();
405                currentProcess = null;
406            }
407            org.objectweb.jac.aspects.gui.Actions.showStatus("Application stopped.");
408        }
409    
410        public void startSlaves()  throws IOException {  
411            File dir = new File(project.getGenerationPath(),name);
412            Vector runCmd = new Vector();
413            runCmd.add("go");
414            runCmd.add(""+getHosts().size());
415            File jar = new File(org.objectweb.jac.core.Jac.getJacRoot()+"jac.jar");
416            runCmd.add("-C");
417            runCmd.add(project.getGenerationPath().getPath()+
418                       System.getProperty("path.separator")+
419                       new File(project.getGenerationPath(),"classes").getPath());
420          
421            String msg="Starting slaves...";
422    
423            org.objectweb.jac.aspects.gui.Actions.showStatus(msg);
424    
425            //Log.trace("ide.run",0,"Run command = "+runCmd);
426            Runtime.getRuntime().exec(
427                (String[])runCmd.toArray(new String[] {}));
428          
429        }
430    
431        /**
432         * Changes a trace for the running process
433         * @param category category of the trace
434         * @param level level of the trace (0=quiet,1=verbose,2=more verbose...)
435         */
436        public void setTrace(String category, Level level) throws Exception {
437            if (currentProcess!=null) {
438                Jac.remoteSetTrace(name,serverName,category,level.toInt());
439            }
440        }
441    
442        public boolean canStartSlaves() {
443            return getHosts().size()>0;
444        }
445    
446        public void generateCode() throws CannotGenerateException, IOException
447        {
448            project.checkGenerationPath();
449            CodeGeneration.createApplicationCode(
450                project,this,new File(project.getGenerationPath().getPath(),name));
451        }
452    
453        /**
454         * Returns available main classes (Classes wich have a static void
455         * main(String[]) method)
456         * @param application the application to return main classes for
457         */
458        public static Collection getMainClasses(Application application) {
459            Vector mainClasses = new Vector();
460            if (application.getProject()!=null) {
461                Iterator it = application.getProject().getPackages().iterator();
462                while (it.hasNext()) {
463                    Package pkg = (Package)it.next();
464                    mainClasses.addAll(pkg.getMainClasses());
465                }
466            }
467            return mainClasses;
468        }
469    }