KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > speedo > genclass > merger > GenClassMerger


1 /**
2  * Copyright (C) 2001-2004 France Telecom R&D
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18 package org.objectweb.speedo.genclass.merger;
19
20 import org.apache.tools.ant.BuildException;
21 import org.apache.tools.ant.taskdefs.MatchingTask;
22 import org.objectweb.asm.Attribute;
23 import org.objectweb.asm.ClassAdapter;
24 import org.objectweb.asm.ClassReader;
25 import org.objectweb.asm.ClassVisitor;
26 import org.objectweb.asm.ClassWriter;
27 import org.objectweb.asm.CodeAdapter;
28 import org.objectweb.asm.CodeVisitor;
29 import org.objectweb.asm.Constants;
30 import org.objectweb.speedo.api.ExceptionHelper;
31 import org.objectweb.speedo.api.SpeedoException;
32 import org.objectweb.speedo.api.SpeedoProperties;
33 import org.objectweb.speedo.genclass.GenClass;
34 import org.objectweb.speedo.generation.enhancer.ClassRenamer;
35 import org.objectweb.speedo.tools.StringReplace;
36 import org.objectweb.util.monolog.Monolog;
37 import org.objectweb.util.monolog.api.BasicLevel;
38 import org.objectweb.util.monolog.api.Logger;
39 import org.objectweb.util.monolog.wrapper.printwriter.LoggerImpl;
40
41 import java.io.File JavaDoc;
42 import java.io.FileInputStream JavaDoc;
43 import java.io.FileOutputStream JavaDoc;
44 import java.io.IOException JavaDoc;
45 import java.util.ArrayList JavaDoc;
46 import java.util.List JavaDoc;
47 import java.util.Set JavaDoc;
48 import java.util.TreeSet JavaDoc;
49
50 /**
51  *
52  * @author S.Chassande-Barrioz
53  */

54 public class GenClassMerger
55 extends MatchingTask {
56
57     public final static String JavaDoc LOGGER_NAME =
58         SpeedoProperties.LOGGER_NAME + ".genclassmerger";
59
60     public final static String JavaDoc GEN_CLASS_NAME
61     = GenClass.class.getName().replace('.', '/');
62
63
64     public final static String JavaDoc[][] CONSTRUCTOR_PARAM = {
65             {"Lorg/objectweb/jorm/type/api/PType;", "ptype"},
66             {"Ljava/lang/String;", "linkedField"},
67             {"Ljava/lang/Object;", "pnameHints"},
68             {"Ljava/lang/String;", "mapperName"}
69     };
70
71     public final static String JavaDoc CONSTRUCTOR_DESC =";"
72         + CONSTRUCTOR_PARAM[0][0]
73                                + CONSTRUCTOR_PARAM[1][0]
74                                                       + CONSTRUCTOR_PARAM[2][0]
75                                                                              + CONSTRUCTOR_PARAM[3][0]
76                                                                                                     + ")V";
77
78     private File JavaDoc src = null;
79
80     private Logger logger = null;
81
82     public GenClassMerger() {
83     }
84
85     public GenClassMerger(Logger logger) {
86         this.logger = logger;
87     }
88
89     public void _setLogger(Logger logger) {
90         this.logger = logger;
91     }
92
93     public File JavaDoc getSrc() {
94         return src;
95     }
96
97     public void setSrc(File JavaDoc src) {
98         this.src = src;
99     }
100
101     public void execute() throws BuildException {
102         if (logger == null) {
103             logger = Monolog.initialize().getLogger(LOGGER_NAME);
104         }
105         String JavaDoc[] pdFiles = super.getDirectoryScanner(src).getIncludedFiles();
106         for(int i=0; i<pdFiles.length; i++) {
107             try {
108                 mergeGenClass(pdFiles[i]);
109             } catch (SpeedoException e) {
110                 String JavaDoc msg = "Error while merging the file " + pdFiles[i]
111                                                                        + " merged" ;
112                 Exception JavaDoc ie = ExceptionHelper.getNested(e);
113                 logger.log(BasicLevel.ERROR, msg, ie);
114                 throw new BuildException(msg, ie);
115             }
116         }
117     }
118
119     public void mergeGenClass(String JavaDoc gcn) throws SpeedoException {
120         IsAbstractVisitor i = new IsAbstractVisitor();
121         ClassReader cr = loadJavaClass(gcn, false);
122         cr.accept(i, false);
123         if (!i.isAbstract) {
124             return;
125         }
126         logger.log(BasicLevel.INFO, "Enhance the generic class " + gcn);
127
128         ClassWriter cw = new ClassWriter(false);
129
130         //Write the original classes
131
ArrayList JavaDoc methods = new ArrayList JavaDoc();
132         ClassMerger m = new ClassMerger(cw, methods, null);
133         cr.accept(m, false);
134
135         //Write the genclass classes
136
Set JavaDoc old = new TreeSet JavaDoc();
137         String JavaDoc t = gcn.substring(0, gcn.length()-6);
138         
139         t = StringReplace.replaceChar(File.separatorChar, '/', t);
140         logger.log(BasicLevel.DEBUG, "t=" + t);
141         
142         old.add(t);
143         m = new ClassMerger(cw,methods, m.getSuperName());
144         ClassRenamer renamer = new ClassRenamer(m, old, t, new LoggerImpl());
145         loadJavaClass(GEN_CLASS_NAME + ".class", false).accept(renamer, false);
146         writeJavaClass(gcn, cw);
147         try {
148             t = StringReplace.replaceChar('/','.', t);
149             logger.log(BasicLevel.DEBUG, "className=" + t);
150             Class.forName(t);
151             
152         } catch (Exception JavaDoc e) {
153             String JavaDoc msg = "Bad merge of the class " + gcn;
154             logger.log(BasicLevel.ERROR, msg, e);
155             throw new SpeedoException(msg, e);
156         }
157     }
158
159     /**
160      * This visitor checks if the class is abstract.
161      */

162     private class IsAbstractVisitor implements ClassVisitor {
163         public boolean isAbstract;
164
165         public void visit(final int version,
166                 final int access,
167                 final String JavaDoc name,
168                 final String JavaDoc superName,
169                 final String JavaDoc[] interfaces,
170                 final String JavaDoc sourceFile) {
171             isAbstract = (access & Constants.ACC_ABSTRACT) != 0;
172         }
173
174         public void visitInnerClass(String JavaDoc s, String JavaDoc s1, String JavaDoc s2, int i) {
175         }
176
177         public void visitField(int i, String JavaDoc s, String JavaDoc s1, Object JavaDoc o, Attribute attrs) {
178         }
179
180         public CodeVisitor visitMethod(int i, String JavaDoc s, String JavaDoc s1, String JavaDoc[] strings, Attribute attrs) {
181             return null;
182         }
183
184         public void visitAttribute(Attribute attribute) {
185         }
186
187         public void visitEnd() {
188         }
189     }
190
191
192     /**
193      * Loads a specified class.
194      * @param filename is the file name of the .class to load. the file name is
195      * a relative patht to the 'src' directory.
196      * @param remove indicates if the .class must be removed
197      * @return the JavaClass loaded
198      * @exception SpeedoException if the file cannot be loaded
199      */

200     protected ClassReader loadJavaClass(String JavaDoc filename,
201             boolean remove) throws SpeedoException {
202         try {
203             File JavaDoc f = new File JavaDoc(src, filename);
204             FileInputStream JavaDoc fis = new FileInputStream JavaDoc(f);
205             ClassReader jclass = new ClassReader(fis);
206             fis.close();
207             if (remove) {
208                 f.delete();
209             }
210             return jclass;
211         } catch (IOException JavaDoc e) {
212             throw new SpeedoException("Error during loading " + filename, e);
213         }
214     }
215
216     /**
217      * Saves the new bytecode of the specified Java class under a specified base
218      * directory.
219      *
220      * @param jclass the Java class that has to be saved
221      * @exception SpeedoException if the file cannot be written
222      */

223     protected void writeJavaClass(final String JavaDoc filename,
224             final ClassWriter jclass)
225     throws SpeedoException {
226         try {
227             File JavaDoc outputFile = new File JavaDoc(src, filename);
228             outputFile.createNewFile();
229             FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc(outputFile);
230             fos.write(jclass.toByteArray());
231             fos.close();
232         } catch (IOException JavaDoc e) {
233             throw new SpeedoException("Cannot write " + filename, e);
234         }
235     }
236
237     /**
238      * 1/ Writes the non abstract methods and the fields of a class.
239      * 2/ Add in the special constructor the field assignement.
240      */

241     private class ClassMerger extends ClassAdapter {
242
243         List JavaDoc methods;
244         String JavaDoc superName;
245         String JavaDoc classname;
246
247         public ClassMerger(ClassVisitor classVisitor,
248                 List JavaDoc methods,
249                 String JavaDoc superName) {
250             super(classVisitor);
251             this.methods = methods;
252             this.superName = superName;
253         }
254
255
256         public String JavaDoc getSuperName() {
257             return superName;
258         }
259
260         /**
261          * Makes the classes no more abstract
262          */

263         public void visit(final int version, final int access,
264                 final String JavaDoc name,
265                 final String JavaDoc superName,
266                 final String JavaDoc[] interfaces,
267                 final String JavaDoc sourceFile) {
268             this.classname = name;
269             this.superName = (this.superName == null ? superName : this.superName);
270             super.cv.visit(version, access ^ Constants.ACC_ABSTRACT,
271                     name, this.superName, interfaces, sourceFile);
272         }
273
274         public CodeVisitor visitMethod(final int access,
275                 final String JavaDoc name,
276                 final String JavaDoc desc,
277                 final String JavaDoc[] exceptions,
278                 final Attribute attrs) {
279             String JavaDoc method = name + " " + desc;
280             if ((access & Constants.ACC_ABSTRACT) == 0
281                     && !methods.contains(method)) {
282                 methods.add(method);
283
284                 CodeVisitor cov = super.cv.visitMethod(access, name, desc, exceptions, attrs);
285                 if (name.equals("<init>") && desc.endsWith(CONSTRUCTOR_DESC)) {
286                     cov = new ConstructorModifier(cov, classname);
287                 }
288                 return cov;
289             } else {
290                 return null;
291             }
292         }
293
294         private class ConstructorModifier extends CodeAdapter {
295             String JavaDoc className;
296             public ConstructorModifier(CodeVisitor codeVisitor, String JavaDoc classname) {
297                 super(codeVisitor);
298                 this.className = classname;
299             }
300
301             public void visitInsn(int i) {
302                 if (i == Constants.RETURN) {
303                     for(int ps = 0; ps<CONSTRUCTOR_PARAM.length; ps++) {
304                         //ALOAD 0
305
cv.visitVarInsn(Constants.ALOAD, 0);
306                         //ALOAD X
307
cv.visitVarInsn(Constants.ALOAD, ps + 2);
308                         //PUTFIELD Y
309
cv.visitFieldInsn(Constants.PUTFIELD,
310                                 className, CONSTRUCTOR_PARAM[ps][1],
311                                 CONSTRUCTOR_PARAM[ps][0]);
312                     }
313                 }
314                 super.visitInsn(i);
315             }
316         }
317     }
318 }
319
Popular Tags