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 com.sun.tools.javac.Main;
022    import gnu.regexp.RE;
023    import gnu.regexp.REException;
024    import gnu.regexp.REMatch;
025    import java.io.BufferedReader;
026    import java.io.ByteArrayInputStream;
027    import java.io.ByteArrayOutputStream;
028    import java.io.FileInputStream;
029    import java.io.FileNotFoundException;
030    import java.io.FileOutputStream;
031    import java.io.FileWriter;
032    import java.io.FilenameFilter;
033    import java.io.IOException;
034    import java.io.InputStreamReader;
035    import java.io.PrintStream;
036    import java.io.Writer;
037    import java.util.Arrays;
038    import java.util.Collection;
039    import java.util.HashSet;
040    import java.util.Hashtable;
041    import java.util.Iterator;
042    import java.util.List;
043    import java.util.Map;
044    import java.util.Set;
045    import java.util.Vector;
046    import java.util.jar.JarEntry;
047    import java.util.jar.JarOutputStream;
048    import java.util.jar.Manifest;
049    import org.apache.log4j.Logger;
050    import org.objectweb.jac.core.rtti.MethodItem;
051    import org.objectweb.jac.core.rtti.NamingConventions;
052    import org.objectweb.jac.lib.Attachment;
053    import org.objectweb.jac.util.Classes;
054    import org.objectweb.jac.util.File;
055    import org.objectweb.jac.util.Files;
056    import org.objectweb.jac.util.LineNumberWriter;
057    import org.objectweb.jac.util.Streams;
058    import org.objectweb.jac.util.Strings;
059    
060    public class CodeGeneration {
061        static Logger logger = Logger.getLogger("ide.compile");
062    
063        /**
064         * Generate code for all the classes and aspects of a project.
065         *
066         * @param project the project
067         * @param baseDir base directory where to put generated files
068         */
069        public static void createProjectCode(Project project, String baseDir) 
070            throws CannotGenerateException, IOException
071        {
072            createJavaCode(project,baseDir);
073            Iterator it = project.getApplications().iterator();
074            while(it.hasNext()) {
075                Application cur = (Application)it.next();
076                createApplicationCode(project, cur, new File(baseDir,cur.getGenerationName()));
077            }
078            print("generation completed for "+project.getName()+".");
079        }
080    
081        public static void createJavaCode(Project project,String baseDir) 
082            throws CannotGenerateException, IOException, FileNotFoundException
083        {
084            Iterator it = Projects.types.getEnumeratedTypes().iterator();
085            while(it.hasNext()) {
086                EnumeratedType enum = (EnumeratedType)it.next();
087                createEnumCode(enum, new File(baseDir,enum.getPackagePath()));
088            }
089            it = project.getPackages().iterator();
090            while(it.hasNext()) {
091                Package cur = (Package)it.next();
092                createPackageCode(project, cur,
093                                  new File(baseDir,cur.getGenerationName()),
094                                  cur.getGenerationName());
095            }        
096        }
097    
098        public static void createEnumCode(EnumeratedType enum, File dir) throws IOException {
099            print("Generating code for enum "+enum.getName()+".");
100            String enumName = Strings.toUSAscii(enum.getName());
101            FileWriter out = new  FileWriter(new File(dir, enumName+".java"));
102            try {
103                out.write("package "+enum.getPackagePath()+";\n");
104                out.write("public interface "+enumName+" {\n");
105                int value = enum.getStartValue();
106                int step = enum.getStep();
107                Iterator it = enum.getNames().iterator();
108                while (it.hasNext()) {
109                    StringBuffer nameBuf = new StringBuffer((String)it.next());
110                    Strings.toUSAscii(nameBuf);
111                    Strings.toUpperCase(nameBuf);
112                    Strings.replace(" '-/+",'_',nameBuf);
113                    Strings.deleteChars("()[]",nameBuf);
114                    String name = nameBuf.toString();
115                    // remove unwanted characters such as '.'
116                    StringBuffer buffer = new StringBuffer(name.length());
117                    for (int i=0; i<name.length(); i++) {
118                        char c = name.charAt(i);
119                        if (c != '.')
120                            buffer.append(c);
121                    }
122                    name = buffer.toString();
123                    out.write("    int "+(Character.isDigit(name.charAt(0))?"_":"")+name+" = "+value+";\n");
124                    value += step;
125                }
126                out.write("}\n");
127            } finally {
128                out.close();
129            }
130        }
131    
132        /**
133         * Generate code for an application (<code>Run</code> and aspect
134         * configurations)
135         *
136         * @param prj the project
137         * @param app the application
138         * @param baseDir the base directory where to put the generated files
139         */
140        public static void createApplicationCode(Project prj,
141                                                 Application app,
142                                                 File baseDir) 
143            throws CannotGenerateException, IOException
144        {
145            Iterator it = app.getAspectConfigurations().iterator();
146            while (it.hasNext()) {
147                AspectConfiguration ac = (AspectConfiguration) it.next();
148                createACFile(prj,ac,baseDir);
149                //createDefaultACFile(prj,ac,baseDir);
150            }
151            createJACFile(prj,app,baseDir);
152        }
153    
154        /**
155         * Generate a warning that the file was automatically generated.
156         *
157         * @param writer writer where to write the warning
158         */
159        static void writeWarning(Writer fw) {
160            try {
161                fw.write("//\n"+
162                         "// WARNING: this file has been automatically generated by JAC\n"+
163                         "// DO NOT MODIFY unless you know what you are doing\n"+
164                         "//\n");
165            } catch(Exception e) {
166                e.printStackTrace();
167            }
168        }
169    
170        // aspect name -> AspectPlugin
171        static transient Map aspectPlugins = new Hashtable();
172        static {
173            aspectPlugins.put("rtti", new RttiPlugin());
174            //aspectPlugins.put("integrity", new IntegrityPlugin());
175            aspectPlugins.put("gui", new GuiPlugin());
176            aspectPlugins.put("persistence", new PersistencePlugin());
177        }
178    
179        /**
180         * Generate aspect configuration code for an aspect of a project.
181         *
182         * @param project the project
183         * @param ac the aspect configuration
184         * @param dir directory where to put the file
185         */
186        static void createACFile(Project project,
187                                 AspectConfiguration ac, File dir) {
188            try {
189                File f = new File(dir,ac.getGenerationName()+".acc");
190                if (f.exists())
191                    f.delete();
192                f.getParentFile().mkdirs();
193                f.createNewFile();
194                FileWriter fw = new FileWriter(f);
195    
196                // Automatically generated config code
197                if (aspectPlugins.containsKey(ac.getName())) {
198                    AspectPlugin plugin =
199                        (AspectPlugin)aspectPlugins.get(ac.getName());
200                    plugin.genConfig(fw,project);
201                }
202    
203                // common default configurations for all classes
204                if (ac.getDefaultConfigurationCode()!=null &&
205                    !ac.getDefaultConfigurationCode().equals("")) {
206                    Collection classes = createClassesList(project);
207                    Iterator itClasses = classes.iterator();
208                    while(itClasses.hasNext()) {
209                        String classname = (String)itClasses.next();
210                        fw.write("class "+classname+" {\n");
211                        fw.write(ac.getDefaultConfigurationCode());
212                        fw.write("\n}\n");
213                    }
214                }
215    
216                //Create Acc ConfigurationCode from the ConfigItem
217                //First creating code from the Project
218                List configItems = project.getConfigItems();
219                Iterator ite = configItems.iterator();
220                fw.write("//CodeGeneration : generate Project code\n");
221                while (ite.hasNext()){
222                    ConfigItem configItem = (ConfigItem)ite.next();
223                    if (configItem.getAspectConfiguration()==ac){
224                        fw.write(configItem.getMethod()+" "+translateParam(configItem));
225                    }
226                }
227                fw.write("//CodeGeneration : end of Project code\n\n");
228                //Iterate on each package of the project
229                ite = project.getPackages().iterator();
230                fw.write("//CodeGeneration : generate Package code\n");
231                while(ite.hasNext()){
232                    Package pack = (Package)ite.next();
233                    generateConfigItemPackageCode(pack,ac,fw);
234                }
235                fw.write("//CodeGeneration : end of Package code\n\n");
236                // main config
237                fw.write(ac.getConfigurationCode());
238                fw.close();
239            } catch(Exception e) {
240                e.printStackTrace();
241            }
242        }
243    
244        /**
245         * Build a list of paths for all the classes of a project.
246         *
247         * @param project the project
248         * @return a collection of Strings which are the paths of the
249         * source files of the classes
250         * @see createClassesList(Package,String)
251         */
252        static Collection createClassesList(Project project) {
253            Vector result = new Vector();
254            Iterator it = project.getPackages().iterator();
255            while(it.hasNext()) {
256                Package cur = (Package)it.next();
257                result.addAll(createClassesList(cur,cur.getGenerationName()));
258            }
259            return result;
260        }
261    
262        /**
263         * Build a list of paths for all the classes of a package and its
264         * subpackages.
265         *
266         * @param package the package
267         * @return a collection of Strings which are the paths of the
268         * source files of the classes
269         */
270        static Collection createClassesList(Package project,String baseDir) {
271            Vector result = new Vector();
272            Iterator it = project.getSubPackages().iterator();
273            while(it.hasNext()) {
274                Package cur = (Package)it.next();
275                result.addAll(createClassesList(cur,baseDir+"."+cur.getGenerationName()));
276            }
277            it = project.getClasses().iterator();
278            while(it.hasNext()) {
279                Class cur = (Class)it.next();
280                result.add(baseDir+"."+cur.getGenerationName());
281            }
282            return result;
283        }
284    
285        /**
286         * Generate the descriptor of an application (the .jac file).
287         *
288         * @param prj the project
289         * @param app the applicatino
290         * @param baseDir directory where to put the <code>.jac</code> file
291         */
292    
293        static void createJACFile(Project prj, Application app, File baseDir) 
294            throws CannotGenerateException, IOException
295        {
296            File f = app.getJacFile();
297            if (f.exists())
298                f.delete();
299            f.getParentFile().mkdirs();
300            f.createNewFile();
301            FileWriter fw = new FileWriter(f);
302             
303            if (app.getMainClass()==null) {
304                throw new CannotGenerateException("No main class defined.");
305            }
306            fw.write("applicationName: "+app.getName()+"\n"+
307                     "launchingClass: "+app.getMainClass().getGenerationFullName()+"\n");
308    
309            if (app.getAspectConfigurations()!=null &&
310                app.getAspectConfigurations().size()>0) {
311                fw.write( "aspects: ");
312                if (app.getAspectConfigurations().size()>0 &&
313                    !((AspectConfiguration)app.getAspectConfigurations().get(0))
314                    .getName().equals("rtti"))
315                {
316                    fw.write( "rtti"
317                              + " \"" + app.getGenerationName()
318                              + "/" + "null.acc\""
319                              + " true ");
320                }
321                Iterator it = app.getAspectConfigurations().iterator();
322                while(it.hasNext()) {
323                    AspectConfiguration cur = (AspectConfiguration)it.next();
324                    if( ((org.objectweb.jac.core.ACManager)org.objectweb.jac.core.ACManager.get())
325                        .isACDeclared(cur.getName()) ) {
326                        fw.write( cur.getName()
327                                  + " \"" + app.getGenerationName()
328                                  + "/" + cur.getGenerationName() + ".acc\""
329                                  + " " + cur.isWoven() + " ");
330                    } else {
331                        fw.write( cur.getAspect().getGenerationFullName()+"AC"
332                                  + " \"" + app.getGenerationName()
333                                  + "/" + cur.getGenerationName() + ".acc\""
334                                  + " " + cur.isWoven() + " ");
335                    }
336                }
337                fw.write("\n\n");
338            }
339    
340            if (app.getHosts()!=null && app.getHosts().size()>0) {
341                fw.write( "\ntopology: ");
342                Iterator it = app.getHosts().iterator();
343                while(it.hasNext()) {
344                    String cur=(String)it.next();
345                    fw.write(cur+" ");
346                }
347                fw.write("\n\n");
348            }
349    
350            if (!app.getIgnoredClasses().isEmpty()) {
351                fw.write("\njac.toNotAdapt: ");
352                Iterator it = app.getIgnoredClasses().iterator();
353                while(it.hasNext()) {
354                    String expr = (String)it.next();
355                    fw.write(expr+" ");
356                }
357                fw.write("\n\n");
358            }
359    
360            fw.close();
361        }
362    
363        /**
364         * Generate code for the classes of a package and its subpackages.
365         *
366         * @param prj the project
367         * @param pkg the package
368         * @param baseDir directory where to put the files of the package
369         * @param ppath java package path (<code>myapp.mypackage</code> for instance)
370         */
371        public static void createPackageCode(Project prj,
372                                             Package pkg,
373                                             File baseDir,
374                                             String ppath) 
375            throws FileNotFoundException, IOException
376        {
377            Iterator it = pkg.getSubPackages().iterator();
378            while (it.hasNext()) {
379                Package cur = (Package)it.next();
380                createPackageCode(prj, cur,
381                                  new File(baseDir,cur.getGenerationName()),
382                                  ppath+"."+cur.getGenerationName());
383            }
384            it = pkg.getClasses().iterator();
385            while (it.hasNext()) {
386                Class cur = (Class)it.next();
387                if (cur instanceof Aspect) {
388                    createAspectCode(prj,(Aspect)cur,baseDir,ppath);
389                } else {
390                    createClassCode(prj,cur,baseDir,ppath);
391                }
392            }
393    
394            it = pkg.getResources().iterator();
395            while (it.hasNext()) {
396                Attachment res = (Attachment)it.next();
397                FileOutputStream out = new FileOutputStream(new File(baseDir,res.getName()));
398                try {
399                    byte[] data = res.getData();
400                    out.write(data,0,data.length);
401                } finally {
402                    out.close();
403                }
404            }
405        }
406    
407        // Class -> ( Method -> (Integer)lineNumber )
408        static transient Hashtable classesLineNumbers = new Hashtable();
409    
410        /**
411         * Returns a Map giving the line number of methods in the generated
412         * java source file.
413         */
414        public static Map getClassLineNumbers(Class c) {
415            Map map = (Map)classesLineNumbers.get(c);
416            if (map==null) {
417                map = new Hashtable();
418                classesLineNumbers.put(c,map);
419            }
420            return map;
421        }
422    
423        /**
424         * Generate the java source code of a class.
425         *
426         * @param prj the project
427         * @param c the class
428         * @param baseDir directory where to put the generated file
429         * @param ppath java package path of the class
430         */
431        public static void createClassCode(Project prj, Class c,
432                                           File baseDir, String ppath) {
433            try {
434                Map lineNumbers = getClassLineNumbers(c);
435                lineNumbers.clear();
436                print("generating "+c.getFullName());
437                File f = new File(baseDir,c.getGenerationName()+".java");
438                classFiles.put(f.getAbsolutePath(),c);
439                if (f.exists())
440                    f.delete();
441                f.getParentFile().mkdirs();
442                f.createNewFile();
443                String shortName = c.getGenerationName();
444                LineNumberWriter output = new LineNumberWriter(Files.newFileWriter(f,"UTF-8"));
445                writeWarning(output);
446                output.write("\npackage "+ppath+";\n\n");
447                String description = c.getDescription();
448    
449                HashSet generatedImports = new HashSet();
450                // Automatic imports for field types
451                Iterator it = c.getFields().iterator();
452                while(it.hasNext()) {
453                    Type type = ((Field)it.next()).getType();
454                    if (!(type instanceof EnumeratedType) &&
455                        type.getPackagePath()!=null && !type.getPackagePath().equals("") 
456                        && !generatedImports.contains(type.getGenerationFullName())) {
457                        output.write("import "+type.getGenerationFullName()+";\n");
458                        generatedImports.add(type.getGenerationFullName());
459                    }
460                }
461    
462                // Imports of the class
463                it = c.getImports().iterator();
464                while(it.hasNext()) {
465                    String imp = (String)it.next();
466                    if (!generatedImports.contains(imp)) {
467                        output.write("import "+imp+";\n");
468                        generatedImports.add(imp);
469                    }
470                }
471    
472                if (description!=null && description.length()>0)
473                    output.write("\n/**\n"+description+"\n*/\n");
474                boolean isInterface = c instanceof Interface;
475                output.write("\npublic "+(c.isAbstract()?"abstract ":"")+
476                             (isInterface?"interface ":"class ")+
477                             shortName+
478                             ((c.getSuperClass() == null)?"":" extends "+
479                              c.getSuperClass().getGenerationFullName()));
480                Set interfaces = c.getInterfaces();
481                if (!interfaces.isEmpty()) {
482                    if (isInterface)
483                        output.write(" extends ");
484                    else 
485                        output.write(" implements ");
486                    joinFullNames(output,interfaces,",");
487                }
488                output.write( " {\n" );
489                List ms = c.getMethods();
490                for (int i=0; i < ms.size(); i++) {
491                    Method method = (Method)ms.get(i);
492                    createMethodCode(output,lineNumbers,method,isInterface);
493                }
494    
495                List fs = c.getFields();
496                for (int i=0; i<fs.size(); i++) {
497                    Field field = (Field)fs.get(i);
498                    createFieldCode(output,lineNumbers,field,isInterface);
499                }
500    
501                List rs = c.getLinks();
502                for (int i=0; i<rs.size(); i++) {
503                    Role role = (Role)rs.get(i);
504                    if (role instanceof RelationRole) {
505                        RelationRole relRole = (RelationRole)role;
506                        RelationLink rel = (RelationLink)role.getLink();
507                        if (relRole.isNavigable()) {
508                            createRelationCode(output,lineNumbers,rel,relRole,isInterface);
509                        }
510                    }
511                }
512    
513                output.write("}\n");
514                output.close();
515                //print("generation fullfilled.");
516            } catch( Exception e) {
517                e.printStackTrace();
518            }
519        }
520    
521        /**
522         * Generate the code for a field, its getter and its setter
523         *
524         * @param output where to write generated code
525         * @param lineNumbers line numbers information will be stored in this map
526         * @param field the field to generate code for
527         * @param isInterface wether the field belongs to an interface
528         */
529        public static void createFieldCode(LineNumberWriter output,
530                                           Map lineNumbers,
531                                           Field field, 
532                                           boolean isInterface)
533            throws IOException
534        {
535            String fieldName = field.getGenerationName();
536            String type = field.getType().getGenerationFullName();
537    
538            if (!(field.isCalculated() || isInterface)) {
539                String description = field.getDescription();
540                if (description!=null && description.length()>0)
541                    output.write("\n/**\n" + description + "\n*/\n");
542                lineNumbers.put(field,new Integer(output.getLines()));
543                output.write("\n    " + field.getPrototype());
544                String defaultValue = field.getDefaultValue();
545                if (defaultValue!=null && !defaultValue.equals("")) {
546                    output.write(" = "+defaultValue);
547                }
548                output.write(";\n");
549            }
550    
551            boolean isStatic = field.isStatic();
552            if (!field.isReadOnly()) {
553                Setter setter = field.getSetter();
554                if (setter==null) {
555                    output.write("\n    /**\n"+
556                                 "     * Sets the value of field "+fieldName+".\n"+
557                                 "     * @param "+fieldName+" value of field "+fieldName+
558                                 "\n     */\n");
559                    lineNumbers.put(field,new Integer(output.getLines()));
560                    createSetter(
561                        output,fieldName,type, isStatic,
562                        field.isStatic()?field.getParent().getGenerationFullName():null,
563                        isInterface);
564                } else {
565                    createMethodCode(output,lineNumbers,setter,isInterface);
566                }
567            }
568    
569            Getter getter = field.getGetter();
570            if (getter==null) {
571                if (!field.isCalculated()) {
572                    output.write("\n    /**\n"+
573                                 "     * Gets the value of field "+fieldName+".\n"+
574                                 "     * @return value of field "+fieldName+
575                                 "\n     */\n");
576                    lineNumbers.put(field,new Integer(output.getLines()));
577                    createGetter(
578                        output,fieldName,type,isStatic,
579                        field.isStatic()?field.getParent().getGenerationFullName():null,
580                        isInterface);
581                }
582            } else {
583                createMethodCode(output,lineNumbers,field.getGetter(),isInterface);
584            }
585        }
586    
587        public static void createRelationCode(LineNumberWriter output,
588                                              Map lineNumbers,
589                                              RelationLink rel,
590                                              RelationRole role,
591                                              boolean isInterface)
592            throws IOException
593        {
594            String roleGen = role.getGenerationName();
595            String type = role.getAbstractType().getGenerationFullName();
596            boolean isCalculated = rel.isCalculated();
597            if (!isCalculated) {
598                output.write("\n    " + role.getPrototype()+";\n");
599                createSetter(output,roleGen,type,false,null,isInterface);
600            }
601            Method getter = role.getGetter();
602            if (getter==null && !isCalculated) {
603                createGetter(output,roleGen,type,false,null,isInterface);
604            } else if (getter!=null) {
605                createMethodCode(output,lineNumbers,getter,isInterface);
606            }
607    
608            if (role.isMultiple() && !isCalculated) {
609                Typed primaryKey = role.getPrimaryKey();
610                type = role.getEnd().getGenerationFullName();
611             
612                Method adder = role.getAdder();
613                if (adder==null) {
614                    createAdder(output,roleGen,type,primaryKey);
615                } else {
616                    createMethodCode(output,lineNumbers,adder,isInterface);
617                }
618    
619                Method remover = role.getRemover();
620                if (remover==null) {
621                    createRemover(output,roleGen,type,primaryKey);
622                } else {
623                    createMethodCode(output,lineNumbers,remover,isInterface);
624                }
625    
626                Method clearer = role.getClearer();
627                if (clearer==null) {
628                    createClearer(output,roleGen);
629                } else {
630                    createMethodCode(output,lineNumbers,clearer,isInterface);
631                }
632                if (primaryKey!=null) {
633                    createIndexGetter(output,role);
634                }
635            }
636        }
637    
638        /**
639         * Generate the code for a method
640         * @param output where to write generated code
641         * @param lineNumbers
642         * @param method the method to generate code for
643         * @param isInterface wether the method belongs to an interface
644         */
645        public static void createMethodCode(LineNumberWriter output,
646                                            Map lineNumbers,
647                                            Method method,
648                                            boolean isInterface)
649            throws IOException
650        {
651            output.write("\n/**\n");
652            String description = method.getDescription();
653            if (description!=null) {
654                output.write(description);
655            }
656            Iterator params = method.getParameters().iterator();
657            while (params.hasNext()) {
658                Parameter param = (Parameter)params.next();
659                output.write("\n@param "+param.getGenerationName()+" "+
660                             param.getDescription());
661            }
662            output.write("\n*/\n");
663            lineNumbers.put(method,new Integer(output.getLines()));
664            //Log.trace("ide.codegen",method.getParent()+"."+method.getGenerationName()+
665            //          " starts at "+output.getLines());
666            output.write("\n    "+method.getModifiers()+" "+
667                         method.getPrototype());
668            if (method.isAbstract() || isInterface) {
669                output.write(";\n");
670            } else {
671                output.write(" {");
672                String body = method.getBody();
673                if (body!=null)
674                    output.write( "\n    "+body);
675                output.write("\n    }\n");
676            }
677        }
678    
679        /**
680         * Generate java source code for an aspect.
681         *
682         * @param prj the project
683         * @param a the aspect
684         * @param baseDir directory where to put the file
685         * @param ppath java package path of the aspect component
686         */
687        public static void createAspectCode(Project prj,Aspect a,
688                                            File baseDir,String ppath) {
689            try {
690                print("generating "+a.getName());
691                File f = new File(baseDir,a.getGenerationName() + "AC.java");
692                if (f.exists())
693                    f.delete();
694                f.getParentFile().mkdirs();
695                f.createNewFile();
696                String shortName = a.getGenerationName();
697                FileWriter fw = new FileWriter(f);
698                writeWarning(fw);
699                fw.write( "\npackage "+ppath+";\n" );
700                fw.write( "import org.objectweb.jac.core.*;\n" );
701                fw.write( "import org.objectweb.jac.core.rtti.*;\n" );
702                fw.write( "import org.objectweb.jac.util.*;\n" );
703                fw.write( "\npublic class "+shortName+
704                          "AC extends org.objectweb.jac.core.AspectComponent");
705                fw.write( " {\n" );
706                fw.write( "\n    public "+shortName+"AC() {");
707                Iterator it = a.getPointcutLinks().iterator();
708                while(it.hasNext()) {
709                    PointcutLink pc = (PointcutLink)it.next();
710                    if(pc.getEnd() instanceof org.objectweb.jac.ide.Class) {
711                        fw.write("\n        pointcut(\""+
712                                 "ALL\",\""+
713                                 ((org.objectweb.jac.ide.Class)pc.getEnd()).getGenerationFullName()+"\",\""+
714                                 pc.getMethodPCD()+"\","+
715                                 "new "+shortName+"Wrapper(this)"+",\""+
716                                 pc.getAspectRole()+"\",\""+
717                                 pc.getHostPCD()+"\",null);");
718                    } else if (pc.getEnd() instanceof Instance) {
719                        fw.write("\n        pointcut(\""+
720                                 ((Instance)pc.getEnd()).getGenerationName()+"\",\""+
721                                 ((org.objectweb.jac.ide.Class)((Instance)pc.getEnd()).getType()).getGenerationName()+"\",\""+
722                                 pc.getMethodPCD()+"\","+
723                                 "new "+shortName+"Wrapper()"+",\""+
724                                 pc.getAspectRole()+"\",\""+
725                                 pc.getHostPCD()+"\");");
726                    }
727                }
728                fw.write("\n    }");
729    
730                fw.write( "\n    public class "+shortName+
731                          "Wrapper extends org.objectweb.jac.core.Wrapper {");
732    
733                fw.write( "\n    public "+shortName+"Wrapper(AspectComponent ac) {");
734                fw.write( "\n        super(ac);");
735                fw.write( "\n    }");
736    
737                List ms = a.getMethods();
738                for (int i=0; i<ms.size(); i++) {
739                    Method method = (Method)ms.get(i);
740                    fw.write("\n    "+method.getModifiers()+" "+method.getPrototype()+" {" );
741                    fw.write("\n    "+method.getBody());
742                    fw.write("\n    }\n");
743                }
744    
745                List fs = a.getFields();
746                for ( int i = 0; i < fs.size(); i++ ) {
747                    Field field=(Field)fs.get(i);
748                    fw.write( "\n    " + field.getPrototype()+";\n" );
749                    //createSetter(fw,field);
750                    //createGetter(fw,field);
751                }
752    
753                /*Vector rs = a.getRelationLinks();
754                  for ( int i = 0; i < rs.size(); i++ ) {
755                  RelationLink rel=(RelationLink)rs.get(i);
756                  fw.write( "\n    " + rel.getPrototype()+";\n" );
757                  createSetter(fw,rel);
758                  createGetter(fw,rel);
759    
760                  if(rel.isMultiple()) {
761                  createAdder(fw,rel);
762                  createRemover(fw,rel);
763                  }            } */
764    
765                fw.write("\n    }");
766                fw.write( "}\n" );
767                fw.close();
768                //print("generation fullfilled.");
769            } catch( Exception e) {
770                e.printStackTrace();
771            }
772        }
773    
774        /**
775         * Generate getter code for collection
776         * @param output write code to this writer
777         * @param name name of the attribute
778         * @param type type of the attribute
779         * @param className the class name if the field is static (null
780         * otherwise) */
781        static void createGetter(Writer output, String name, String type,
782                                 boolean isStatic,String className, 
783                                 boolean isInterface)
784            throws IOException
785        {
786            output.write("\n    "+(isInterface?"":"public ")+
787                         (isStatic?"static ":"")+type+" get"+
788                         NamingConventions.capitalize(name)+"()");
789            if (isInterface) {
790                output.write(";\n");
791            } else {
792                output.write(" {\n");
793                output.write("        return "+name+";\n");
794                output.write("    }\n");
795            }
796        }
797    
798        /**
799         * Generate setter code for collection
800         * @param output write code to this writer
801         * @param name name of the attribute
802         * @param type type of the attribute
803         * @param className the class name if the field is static (null
804         * otherwise) */
805        static void createSetter(Writer output, String name, String type,
806                                 boolean isStatic, String className, 
807                                 boolean isInterface)
808            throws IOException
809        {
810            output.write("\n    "+(isInterface?"":"public")+
811                         (isStatic?" static":"")+" void "+getSetterName(name)+"("+
812                         type+" value)");
813            if (isInterface) {
814                output.write(";\n");
815            } else {
816                output.write(" {\n");
817                if(className==null) {
818                    output.write("        this."+name+"=value;\n");
819                } else {
820                    output.write("        "+className+"."+name+"=value;\n");
821                }
822                output.write("    }\n");
823            }
824        }
825    
826        /**
827         * Returns the setter's name that corresponds to the given field's
828         * name. */
829    
830        public static String getSetterName(String fieldName) {
831            return "set"+NamingConventions.capitalize(fieldName);
832        }
833    
834        /**
835         * Returns the getter's name that corresponds to the given field's
836         * name. */
837    
838        public static String getGetterName(String fieldName) {
839            return "get"+NamingConventions.capitalize(fieldName);
840        }
841    
842        /**
843         * Returns the adder's name that corresponds to the given
844         * collection's name. */
845    
846        public static String getAdderName(String fieldName) {
847            String fn = NamingConventions.getNormalizedString(fieldName);
848            fn = Projects.plurals.getSingular(fn);
849            return "add"+fn;
850        }
851    
852        /**
853         * Returns the clearer's name that corresponds to the given
854         * collection's name. */
855    
856        public static String getClearerName(String fieldName) {
857            String fn = NamingConventions.getNormalizedString(fieldName);
858            fn = Projects.plurals.getSingular(fn);
859            return "clear"+fn;
860        }
861    
862        /**
863         * Returns the remover's name that corresponds to the given
864         * collection's name. */
865    
866        public static String getRemoverName(String fieldName) {
867            String fn = NamingConventions.getNormalizedString(fieldName);
868            fn = Projects.plurals.getSingular(fn);
869            return "remove"+fn;
870        }
871    
872        public static String keyWrapper(Typed keyField, String value) {
873            if (keyField.getType().isPrimitive()) {
874                return "new "+Classes.getPrimitiveTypeWrapper(keyField.getType().getName())+"("+value+")";
875            } else {
876                return value;
877            }
878        }
879    
880        /**
881         * Generate adder code for collection
882         *
883         * @param output write code to this writer
884         * @param name name of the collection attribute
885         * @param type type of the collection attribute
886         */
887        static void createAdder(Writer output, String name, String type, 
888                                Typed primaryKey)
889            throws IOException
890        {
891            output.write("\n    public void "+getAdderName(name)+"("+type+" value) {\n");
892            if (primaryKey==null)
893                output.write("        "+name+".add(value);\n");
894            else
895                output.write("        "+name+".put("+
896                             keyWrapper(primaryKey,"value."+getGetterName(primaryKey.getGenerationName())+"()")+
897                             ",value);\n");
898            output.write("    }\n");
899        }
900    
901    
902        /**
903         * Generate getter for indexed collection
904         *
905         * @param output write code to this writer
906         * @param name name of the collection attribute
907         * @param type type of the collection attribute
908         */
909        static void createIndexGetter(Writer output, RelationRole role)
910            throws IOException
911        {
912            Typed primaryKey = role.getPrimaryKey();
913            String keyName = primaryKey.getGenerationName();
914            String returnType = role.getEnd().getGenerationName();
915            output.write("\n    public "+returnType+
916                         " get"+Projects.plurals.getSingular(NamingConventions.getNormalizedString(role.getGenerationName()))+"("+
917                         role.getPrimaryKey().getType().getGenerationName()+" "+
918                         keyName+") {\n");
919            output.write("        return ("+returnType+")"+role.getGenerationName()+".get("+
920                         keyWrapper(primaryKey,keyName)+
921                         ");\n");
922            output.write("    }\n");
923        }
924    
925        /**
926         * Generate remover code for collection
927         * @param output write code to this writer
928         * @param name name of the collection attribute
929         * @param type type of the collection attribute
930         */
931        static void createRemover(Writer output, String name, String type, Typed primaryKey)
932            throws IOException
933        {
934            output.write("\n    public void "+getRemoverName(name)+"("+type+" value) {\n");
935            if (primaryKey==null) {
936                output.write("        "+name+".remove(value);\n");
937            } else {
938                output.write("        "+name+".remove("+
939                             keyWrapper(primaryKey,"value."+getGetterName(primaryKey.getGenerationName())+"()")+
940                             ");\n");
941            }
942            output.write("    }\n");
943        }
944    
945        /**
946         * Generate clearer code for collection
947         *
948         * @param output write code to this writer
949         * @param name name of the collection attribute
950         * @param type type of the collection attribute
951         */
952        static void createClearer(Writer output, String name)
953            throws IOException
954        {
955            String fn = NamingConventions.getNormalizedString(name);
956            output.write("\n    public void clear"+
957                         fn+"() {\n");
958            output.write("        "+name+".clear();\n");
959            output.write("    }\n");
960        }
961    
962        /**
963         * Build a list of the java files for a project.
964         *
965         * @param project the project
966         * @param baseDir base directory for the files
967         * @param list adds the filenames to this list
968         */
969        static void createJavaFilesList(Project project, File baseDir, List list) {
970            Iterator it = Projects.types.getEnumeratedTypes().iterator();
971            while(it.hasNext()) {
972                EnumeratedType enum = (EnumeratedType)it.next();
973                list.add(new File(baseDir,enum.getPackagePath()+
974                                  System.getProperty("file.separator")+
975                                  Strings.toUSAscii(enum.getName())+".java").getPath());
976            }
977    
978    
979            it = project.getPackages().iterator();
980            while(it.hasNext()) {
981                Package cur = (Package)it.next();
982                createJavaFilesList(cur,
983                                    new File(baseDir,cur.getGenerationName()),
984                                    list);
985            }
986        }
987    
988        /**
989         * Build a list of the java files for a package.
990         *
991         * @param pkg the package
992         * @param baseDir base directory for the files
993         * @param list adds to filenames to this list
994         */
995        static void createJavaFilesList(Package pkg, File baseDir, List list) {
996            Iterator it = pkg.getSubPackages().iterator();
997            while(it.hasNext()) {
998                Package cur = (Package)it.next();
999                createJavaFilesList(cur,
1000                                    new File(baseDir,cur.getGenerationName()),
1001                                    list);
1002            }
1003            it = pkg.getClasses().iterator();
1004            while(it.hasNext()) {
1005                Class cl = (Class)it.next();
1006                if (cl instanceof Aspect) {
1007                    list.add(new File(baseDir,cl.getGenerationName()+"AC.java").getPath());
1008                } else {
1009                    list.add(new File(baseDir,cl.getGenerationName()+".java").getPath());
1010                }
1011            }
1012    
1013            it = pkg.getResources().iterator();
1014            while(it.hasNext()) {
1015                Attachment res = (Attachment)it.next();
1016                if ("text/x-java".equals(res.getMimeType())) {
1017                    list.add(new File(baseDir,res.getName()).getPath());
1018                }
1019            }
1020        }
1021    
1022        /**
1023         * Build a space separated list of the root packages source
1024         * directories of a project.
1025         *
1026         * @param project the project
1027         * @param baseDir base directory of the project
1028         * @return a String
1029         */
1030        static String createPackageFilesList(Project project,String baseDir) {
1031            StringBuffer result =
1032                new StringBuffer((baseDir.length()+10)*project.getPackages().size());
1033            Iterator it = project.getPackages().iterator();
1034            while(it.hasNext()) {
1035                Package cur = (Package)it.next();
1036                result.append(baseDir + System.getProperty("file.separator")
1037                              + cur.getGenerationName() + " ");
1038            }
1039            return result.toString();
1040        }
1041    
1042        // filename -> Class
1043        static transient Hashtable classFiles = new Hashtable();
1044    
1045        /**
1046         * Get the class corresponding to a filename
1047         */
1048        static Class filenameToClass(String filename) {
1049            Class cl = null;
1050            if ((cl = (Class)classFiles.get(filename))!=null) {
1051                return cl;
1052            } else {
1053                logger.error("Cannot find Class for filename "+filename);
1054                return null;
1055            }
1056        }
1057    
1058        public static Errors generateAndCompileProjectCode(Project project, String baseDir)
1059            throws CannotGenerateException, CannotCompileException, IOException, InterruptedException
1060        {
1061            createProjectCode(project,baseDir);
1062            return compileProjectCode(project);
1063        }
1064    
1065        /**
1066         * Run compilation command for a project.
1067         *
1068         * @param project the project to compile
1069         * @return A list of errors that occured during compilation.
1070         */
1071        public static Errors compileProjectCode(Project project)
1072            throws CannotCompileException, IOException, InterruptedException
1073        {
1074            File baseDir = project.getGenerationPath();
1075            Vector cmdList = new Vector();
1076            if (!project.getUseToolsJavac())
1077                cmdList.add(project.getCompilerCommand().toString());
1078            String[] options = Strings.split(project.getCompilerOptions()," ");
1079            for (int i=0; i<options.length; i++) {
1080                cmdList.add(options[i]);
1081            }
1082    
1083            File classesDir = project.getClassesDir();
1084            cmdList.add("-d");
1085            cmdList.add(classesDir.getPath());
1086    
1087            // Force UTF-8 since we generate sources with this encoding
1088            cmdList.add("-encoding");
1089            cmdList.add("UTF-8");
1090    
1091            String classpathString = null;
1092            Collection classpath = new Vector();
1093            classpath.addAll(project.getClasspath());
1094            if (!classpath.contains(baseDir)) {
1095                classpath.add(baseDir);
1096            }
1097            if (!classpath.contains(classesDir)) {
1098                classpath.add(classesDir);
1099            }
1100    
1101            String jacRoot = org.objectweb.jac.core.Jac.getJacRoot();
1102            File jacClasses = new File(jacRoot,"classes");
1103            if (jacClasses.exists() && !classpath.contains(jacClasses)) {
1104                classpath.add(jacClasses);
1105            }
1106    
1107            File jacJar = new File(jacRoot+"jac.jar");
1108            if (jacJar.exists() && !classpath.contains(jacJar)) {
1109                classpath.add(jacJar);
1110            }
1111    
1112            File jacDir = new File(jacRoot,"lib");
1113            java.io.File jars[] = jacDir.listFiles(
1114                new FilenameFilter() {
1115                        public boolean accept(java.io.File file, String name) {
1116                            return name.endsWith(".jar");
1117                        }
1118                    }
1119            );
1120            if (jars!=null)
1121                    classpath.addAll(Arrays.asList(jars));
1122            String sep = System.getProperty("file.separator");
1123            classpath.add(new File(jacRoot+sep+"lib"+sep+"opt","jasperreports.jar"));
1124    
1125            classpathString = Strings.createPathString(classpath);
1126    
1127            logger.info("Classpath = "+classpathString);
1128            if (classpathString!=null) {
1129                cmdList.add("-classpath");
1130                cmdList.add(classpathString);
1131            }
1132    
1133            createJavaFilesList(project,baseDir,cmdList);
1134    
1135            File f = new File(baseDir, "classes");
1136            if (!f.exists())
1137                f.mkdir();
1138    
1139            logger.info("CMD = "+cmdList);
1140            print("compiling project "+project.getName()+"...");
1141    
1142            BufferedReader reader = null;
1143            final String[] args = (String[])cmdList.toArray(new String[] {});
1144            if (project.getUseToolsJavac()) {
1145                PrintStream oldErr = System.err;
1146                ByteArrayOutputStream out = new ByteArrayOutputStream();
1147                System.setErr(new PrintStream(out));
1148                int res = Main.compile(args);
1149                System.setErr(oldErr);
1150                reader = new BufferedReader(
1151                    new InputStreamReader(
1152                        new ByteArrayInputStream(out.toByteArray())));
1153            } else {
1154                Process comp;
1155                try {
1156                    comp = Runtime.getRuntime().exec(args);
1157                } catch (IOException e) {
1158                    throw new CannotCompileException(
1159                        "Failed to start compilation process, is `"+
1160                        project.getCompilerCommand()+"' in your path?");
1161                }
1162                reader = new BufferedReader(
1163                    new InputStreamReader(comp.getErrorStream()));
1164                logger.debug("waiting for compilation to finish "+comp);
1165            }
1166    
1167            Vector errors = new Vector();
1168            String line;
1169            try {
1170                RE re = new RE("^([^:]+):([0-9]+)");
1171                RE emptyLineRE = new RE("^[         ]*$");
1172                while ((line=reader.readLine())!=null) {
1173                    //Log.trace("ide.compile",line);
1174                    REMatch match;
1175                    if ((match=re.getMatch(line))!=null) {
1176                        //Log.trace("ide.compile",
1177                        //          "New ERROR : "+match.toString(1)+":"+match.toString(2));
1178                        errors.add(new Error(match.toString(1),
1179                                             Integer.parseInt(match.toString(2)),
1180                                             line,
1181                                             filenameToClass(match.toString(1))));
1182                    } else if (emptyLineRE.getMatch(line)==null) {
1183                        errors.add(new Error(line));
1184                    }
1185                }
1186            } catch (REException e) {
1187                throw new CannotCompileException(e.getMessage());
1188            }
1189            //Log.trace("ide.compile","Found "+errors.size()+" Errors.");
1190    
1191            print("compilation done.");
1192            return errors.isEmpty()?null:new Errors(errors);
1193        }
1194    
1195        /**
1196         * Generated javadoc documentation for a project
1197         */
1198        public static void documentProjectCode(Project project,String baseDir) {
1199            String list = createPackageFilesList(project,baseDir);
1200            File f = new File(project.getGenerationPath(),"doc");
1201            if (!f.exists())
1202                f.mkdir();
1203            String cmd = "javadoc -d "+new File(project.getGenerationPath(),"classes")+" "+list;
1204            //Log.trace("ide.compile","CMD = "+cmd);
1205            // to do...
1206        }
1207    
1208        /**
1209         * Print status message.
1210         */
1211        static void print(String msg) {
1212            org.objectweb.jac.aspects.gui.Actions.showStatus(msg);
1213        }
1214    
1215        /**
1216         * Generate the ACC configuration code from the ConfigItems
1217         * @param pack package to generate config for
1218         * @param ac the aspect configuration to generate code for
1219         * @param fw generate code to this writer
1220         * @throws IOException
1221         */
1222        static void generateConfigItemPackageCode(Package pack, AspectConfiguration ac,
1223                                                  Writer fw)
1224            throws IOException
1225        {
1226            AccGenState state = new AccGenState(fw);
1227            Iterator iteClass = pack.getClasses().iterator();
1228            //Iterate the Classes in the package
1229            while (iteClass.hasNext()) {
1230                Class c = (Class)iteClass.next();
1231    
1232                //iterate the config of the Class
1233                Iterator iteClassConfig = c.getConfigItems().iterator();
1234                while (iteClassConfig.hasNext()) {
1235                    ConfigItem configItem = (ConfigItem)iteClassConfig.next();
1236                    if (configItem.getAspectConfiguration()==ac){
1237                        state.openClass(c);
1238                        state.write(translateParam(configItem));
1239                    }
1240                }
1241                //End of the iteration on the class ConfigItem
1242    
1243                //iterate the class field
1244                Iterator iteField = c.getFields().iterator();
1245                while (iteField.hasNext()) {
1246                    Field field = (Field)iteField.next();
1247                    //Iteratate the ConfigItem
1248                    Iterator iteFieldConfig = field.getConfigItems().iterator();
1249                    while (iteFieldConfig.hasNext()) {
1250                        ConfigItem configItem = (ConfigItem)iteFieldConfig.next();
1251                        if (configItem.getAspectConfiguration()==ac){
1252                            state.openField(c,field);
1253                            state.write(translateParam(configItem));
1254                        }
1255                    }
1256                    state.closeMember();
1257                }
1258                //end of the ConfigItem of the field Class
1259    
1260                //iterate the Class Method
1261                Iterator iteMethod = c.getMethods().iterator();
1262                while (iteMethod.hasNext()) {
1263                    Method method = (Method)iteMethod.next();
1264                    //Iteratate the ConfigItem
1265                    Iterator iteMethodConfig = method.getConfigItems().iterator();
1266                    while (iteMethodConfig.hasNext()) {
1267                        ConfigItem configItem = (ConfigItem)iteMethodConfig.next();
1268                        if (configItem.getAspectConfiguration()==ac){
1269                            state.openMethod(c,method);
1270                            state.write(translateParam(configItem));
1271                        }
1272                    }
1273                    state.closeMember();
1274                }
1275                //End of the class Method Iteration
1276    
1277                //iterate the links between class
1278                /* Not really the Relation Links
1279                   Iterator iteLinks=c.getRelationLinks().iterator();
1280                   while(iteLinks.hasNext()){
1281                   RelationLink link=(RelationLink)iteLinks.next();
1282                   Iterator iteLinkConfig=link.getConfigItems().iterator();
1283                   fw.write("   attribute "+link.getGenerationName()+" {\n");
1284                   while(iteLinkConfig.hasNext()){
1285                   ConfigItem item=(ConfigItem)iteLinkConfig.next();
1286                   if (item.getAspectConfiguration()==ac){
1287                   fw.write("      "+translateParam(configItem));
1288                   }
1289                   }
1290                   fw.write("   }\n");
1291                   }
1292                */
1293                //end of the Class links iteration
1294                state.closeClass();
1295    
1296            }
1297    
1298            //Iterate the sub package
1299            Iterator itePackage = pack.getSubPackages().iterator();
1300            while (itePackage.hasNext()) {
1301                Package apack = (Package)itePackage.next();
1302                generateConfigItemPackageCode(apack, ac, fw);
1303            }
1304        }
1305    
1306        /**
1307         * Return a string representing the call of method on ModelElement
1308         * element with param param
1309         * @param config the configItem of method
1310         * @return a valid string that the ACCParser will understand */
1311        public final static String translateParam(ConfigItem config){
1312            MethodItem method=config.getMethod();
1313            if (method==null || "".equals(method.getName()))
1314                return "";
1315            StringBuffer result=new StringBuffer();
1316            result.append(method.getName()+" ");
1317            Iterator params = config.getParam().iterator();
1318            while (params.hasNext()) {
1319                String s = (String)params.next();
1320                //todo if s contain " or keycode we should add/replace some \"
1321                int posBefore = 0, posAfter = 0;
1322                result.append("\"");
1323                while (posBefore!=-1){
1324                    posAfter=s.indexOf('\"',posBefore);
1325                    if (posAfter==-1){
1326                        result.append(s.substring(posBefore));
1327                        posBefore = -1;
1328                    }else{
1329                        result.append(s.substring(posBefore,posAfter)+"\\\"");
1330                        if (posAfter==s.length()-1){
1331                            posBefore = -1;
1332                        }else{
1333                            posBefore = posAfter+1;
1334                        }
1335                    }
1336                }
1337                result.append("\" ");
1338            }
1339            result.append(";\n");
1340            return result.toString();
1341        }
1342    
1343        /**
1344         * Write the full names of the items of a collection, separated by
1345         * a string.
1346         * @param out where to write 
1347         * @param items a collection of ModelElements
1348         * @param separator use this string as a separator
1349         */
1350        public static void joinFullNames(Writer out, Collection items, String separator) 
1351            throws IOException
1352        {
1353            Iterator it = items.iterator();
1354            while (it.hasNext()) {
1355                out.write(((ModelElement)it.next()).getGenerationFullName());
1356                if (it.hasNext())
1357                    out.write(separator);
1358            }
1359        }
1360    
1361        // Projects mixin methods
1362        
1363        public static void generateCode(Projects projects) throws Exception {
1364            Iterator it = projects.getProjects().iterator();
1365            while (it.hasNext()) {
1366                Project p = (Project)it.next();
1367                generateCode(p);
1368            }
1369        }
1370    
1371        public static Errors compile(Projects projects) throws Exception {
1372            Iterator it = projects.getProjects().iterator();
1373            while (it.hasNext()) {
1374                Project p = (Project)it.next();
1375                Errors errors = null;
1376                errors = compile(p);
1377                if (errors!=null) {
1378                    return errors;
1379                }
1380            }
1381            return null;
1382        }
1383    
1384        public static Errors generateAndCompile(Projects projects) throws Exception {
1385            Iterator it = projects.getProjects().iterator();
1386            while (it.hasNext()) {
1387                Project p = (Project)it.next();
1388                Errors errors = null;
1389                errors = generateAndCompile(p);
1390                if (errors!=null) {
1391                    return errors;
1392                }
1393            }
1394            return null;
1395        }
1396    
1397        // Package mixin methods
1398    
1399        public static void generateCode(Package pkg) throws Exception {
1400            Project project = pkg.getProject();
1401            project.checkGenerationPath();
1402            createPackageCode(
1403                project,
1404                pkg,
1405                new File(project.getGenerationPath().getPath(),pkg.getPath()),
1406                pkg.getPPath());
1407        }
1408    
1409        // Class mixin methods
1410    
1411        public static void generateCode(Class cl) throws Exception {
1412            Package pkg = cl.getContainer();
1413            Project project = pkg.getProject();
1414            project.checkGenerationPath();
1415            createClassCode(
1416                project,
1417                cl,
1418                new File(project.getGenerationPath().getPath(),pkg.getPath()),
1419                pkg.getPPath());
1420        }
1421    
1422        // Project mixin methods
1423    
1424        public static void generateCode(Project project) throws Exception {
1425            File generationPath = project.getGenerationPath();
1426            if (generationPath!=null) {
1427                createProjectCode(project,generationPath.getPath());
1428            } else { 
1429                throw new CannotGenerateException(
1430                    "Project \""+project.getName()+"\" does not have a generation path");
1431            }
1432        }
1433    
1434        public static void generateJavaCode(Project project) throws Exception {
1435            File generationPath = project.getGenerationPath();
1436            if (generationPath!=null) {
1437                createJavaCode(project,generationPath.getPath());
1438            } else { 
1439                throw new CannotGenerateException(
1440                    "Project \""+project.getName()+"\" does not have a generation path");
1441            }
1442        }
1443    
1444        public static Errors compile(Project project) 
1445            throws CannotCompileException, IOException, InterruptedException 
1446        {
1447            File generationPath = project.getGenerationPath();
1448            if (generationPath!=null) {
1449                return compileProjectCode(project);
1450            } else {
1451                throw new CannotCompileException(
1452                    "Project \""+project.getName()+"\" does not have a generation path");
1453            }
1454        }
1455    
1456        public static Errors generateAndCompile(Project project) 
1457            throws CannotGenerateException, CannotCompileException, 
1458                   IOException, InterruptedException, Exception
1459        {
1460            generateJavaCode(project);
1461            return compile(project);
1462        }
1463    
1464        
1465        /**
1466         * Creates a JAR file containing all the .class files
1467         */
1468        public static void createJAR(Project project) throws IOException {
1469            createManifest(project);
1470            File generationPath = project.getGenerationPath();
1471            JarOutputStream out = 
1472                new JarOutputStream(
1473                    new FileOutputStream(
1474                        new File(
1475                            generationPath,
1476                            project.getGenerationName()+".jar")),
1477                    new Manifest(
1478                        new FileInputStream(
1479                            new File(project.getManifestDir(), "MANIFEST.MF" )))
1480                );
1481    
1482            // Add class files
1483            File classesDir = project.getClassesDir();
1484            Iterator it = 
1485                project.getClassesDir().listFilesRecursively(
1486                    new FilenameFilter() {
1487                            public boolean accept(java.io.File file, String name) {
1488                                return name.endsWith(".class");
1489                            }
1490                        }
1491                ).iterator();
1492            while (it.hasNext()) {
1493                File classFile = (File)it.next();
1494                JarEntry entry = new JarEntry(classFile.getRelativePath(classesDir).replace('\\','/'));
1495                out.putNextEntry(entry);
1496                FileInputStream input = new FileInputStream(classFile);
1497                Streams.copy(input,out);
1498                out.closeEntry();
1499            }
1500            
1501            // Add .acc and .jac files
1502            it = project.getApplications().iterator();
1503            while (it.hasNext()) {
1504                Application application = (Application)it.next();
1505                Iterator j = application.getAspectConfigurations().iterator();
1506                File appDir = new File(generationPath,application.getGenerationName());
1507                while (j.hasNext()) {
1508                    AspectConfiguration ac = (AspectConfiguration)j.next();
1509                    File accFile = new File(appDir,ac.getGenerationName()+".acc");
1510                    JarEntry entry = 
1511                        new JarEntry(
1512                            accFile.getRelativePath(generationPath).replace('\\','/'));
1513                    out.putNextEntry(entry);
1514                    FileInputStream input = new FileInputStream(accFile);
1515                    Streams.copy(input,out);
1516                    out.closeEntry();
1517                }
1518                File jacFile = application.getJacFile();
1519                JarEntry entry = new JarEntry(jacFile.getRelativePath(generationPath));
1520                out.putNextEntry(entry);
1521                FileInputStream input = new FileInputStream(jacFile);
1522                Streams.copy(input,out);
1523                out.closeEntry();
1524            }
1525    
1526            // Add external files
1527            it = project.getExternalFiles().entrySet().iterator();
1528            while (it.hasNext()) {
1529                Map.Entry entry = (Map.Entry)it.next();
1530                JarEntry jarEntry = new JarEntry((String)entry.getKey());
1531                out.putNextEntry(jarEntry);
1532                FileInputStream input = new FileInputStream((File)entry.getValue());
1533                Streams.copy(input,out);
1534                out.closeEntry();
1535            }
1536    
1537            // Add resources
1538            it = project.getAllResources().entrySet().iterator();
1539            while (it.hasNext()) {
1540                Map.Entry entry = (Map.Entry)it.next();
1541                Package pkg = (Package)entry.getKey();
1542                Attachment res = (Attachment)entry.getValue();
1543                JarEntry jarEntry = 
1544                    new JarEntry(
1545                        pkg.getGenerationName()+'/'+res.getName());
1546                out.putNextEntry(jarEntry);
1547                ByteArrayInputStream input = new ByteArrayInputStream(res.getData());
1548                Streams.copy(input,out);
1549                out.closeEntry();            
1550            }
1551            out.close();
1552        }
1553    
1554        public static void createManifest(Project project) throws IOException {
1555            File file = project.getManifestDir();
1556            file.mkdir();
1557            if (!file.exists())
1558                    new IOException("Could not create META-INF directory");
1559                    
1560            FileWriter out = 
1561                    new FileWriter(new File(project.getManifestDir(), "MANIFEST.MF"));
1562            out.write("Manifest-Version: 1.0\n\n\n\n");
1563    
1564            // Add class files
1565            File classesDir = project.getClassesDir();
1566            Iterator it = 
1567                project.getClassesDir().listFilesRecursively(
1568                    new FilenameFilter() {
1569                            public boolean accept(java.io.File file, String name) {
1570                                return name.endsWith(".class");
1571                            }
1572                        }
1573                ).iterator();
1574            while (it.hasNext()) {
1575                File classFile = (File)it.next();
1576                out.write("Name: ");
1577                out.write(classFile.getRelativePath(classesDir).replace('\\','/') );
1578                out.write("\nJava-Bean: True\n\n");
1579            }
1580    
1581            out.close();
1582        }
1583    
1584        // AspectConfiguration mixin methods
1585    
1586        public static void generateCode(AspectConfiguration ac) throws Exception {
1587            Project project = ac.getApplication().getProject();
1588            project.checkGenerationPath();
1589            CodeGeneration.createACFile(
1590                project,ac,
1591                new File(project.getGenerationPath().getPath(),ac.getApplication().getGenerationName()));
1592        }
1593    
1594        public static void generateAndReload(AspectConfiguration ac) throws Throwable {
1595            generateCode(ac);
1596            ac.reload();
1597        }
1598    }