1 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 ; 42 import java.io.FileInputStream ; 43 import java.io.FileOutputStream ; 44 import java.io.IOException ; 45 import java.util.ArrayList ; 46 import java.util.List ; 47 import java.util.Set ; 48 import java.util.TreeSet ; 49 50 54 public class GenClassMerger 55 extends MatchingTask { 56 57 public final static String LOGGER_NAME = 58 SpeedoProperties.LOGGER_NAME + ".genclassmerger"; 59 60 public final static String GEN_CLASS_NAME 61 = GenClass.class.getName().replace('.', '/'); 62 63 64 public final static String [][] 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 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 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 getSrc() { 94 return src; 95 } 96 97 public void setSrc(File 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 [] 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 msg = "Error while merging the file " + pdFiles[i] 111 + " merged" ; 112 Exception 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 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 ArrayList methods = new ArrayList (); 132 ClassMerger m = new ClassMerger(cw, methods, null); 133 cr.accept(m, false); 134 135 Set old = new TreeSet (); 137 String 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 e) { 153 String msg = "Bad merge of the class " + gcn; 154 logger.log(BasicLevel.ERROR, msg, e); 155 throw new SpeedoException(msg, e); 156 } 157 } 158 159 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 name, 168 final String superName, 169 final String [] interfaces, 170 final String sourceFile) { 171 isAbstract = (access & Constants.ACC_ABSTRACT) != 0; 172 } 173 174 public void visitInnerClass(String s, String s1, String s2, int i) { 175 } 176 177 public void visitField(int i, String s, String s1, Object o, Attribute attrs) { 178 } 179 180 public CodeVisitor visitMethod(int i, String s, String s1, String [] 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 200 protected ClassReader loadJavaClass(String filename, 201 boolean remove) throws SpeedoException { 202 try { 203 File f = new File (src, filename); 204 FileInputStream fis = new FileInputStream (f); 205 ClassReader jclass = new ClassReader(fis); 206 fis.close(); 207 if (remove) { 208 f.delete(); 209 } 210 return jclass; 211 } catch (IOException e) { 212 throw new SpeedoException("Error during loading " + filename, e); 213 } 214 } 215 216 223 protected void writeJavaClass(final String filename, 224 final ClassWriter jclass) 225 throws SpeedoException { 226 try { 227 File outputFile = new File (src, filename); 228 outputFile.createNewFile(); 229 FileOutputStream fos = new FileOutputStream (outputFile); 230 fos.write(jclass.toByteArray()); 231 fos.close(); 232 } catch (IOException e) { 233 throw new SpeedoException("Cannot write " + filename, e); 234 } 235 } 236 237 241 private class ClassMerger extends ClassAdapter { 242 243 List methods; 244 String superName; 245 String classname; 246 247 public ClassMerger(ClassVisitor classVisitor, 248 List methods, 249 String superName) { 250 super(classVisitor); 251 this.methods = methods; 252 this.superName = superName; 253 } 254 255 256 public String getSuperName() { 257 return superName; 258 } 259 260 263 public void visit(final int version, final int access, 264 final String name, 265 final String superName, 266 final String [] interfaces, 267 final String 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 name, 276 final String desc, 277 final String [] exceptions, 278 final Attribute attrs) { 279 String 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 className; 296 public ConstructorModifier(CodeVisitor codeVisitor, String 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 cv.visitVarInsn(Constants.ALOAD, 0); 306 cv.visitVarInsn(Constants.ALOAD, ps + 2); 308 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 |