KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > loader > enhancer > EnhancerFixup


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.loader.enhancer;
31
32 import com.caucho.bytecode.*;
33 import com.caucho.java.WorkDir;
34 import com.caucho.java.gen.JavaClassGenerator;
35 import com.caucho.loader.DynamicClassLoader;
36 import com.caucho.util.L10N;
37 import com.caucho.vfs.JarPath;
38 import com.caucho.vfs.Path;
39 import com.caucho.vfs.ReadStream;
40 import com.caucho.vfs.Vfs;
41 import com.caucho.vfs.WriteStream;
42
43 import java.net.URL JavaDoc;
44 import java.util.ArrayList JavaDoc;
45 import java.util.logging.Logger JavaDoc;
46
47 /**
48  * Class loader which checks for changes in class files and automatically
49  * picks up new jars.
50  *
51  * <p>DynamicClassLoaders can be chained creating one virtual class loader.
52  * From the perspective of the JDK, it's all one classloader. Internally,
53  * the class loader chain searches like a classpath.
54  */

55 public class EnhancerFixup {
56   private static final L10N L = new L10N(EnhancerFixup.class);
57   private static final Logger JavaDoc log = Logger.getLogger(EnhancerFixup.class.getName());
58
59   private static final int ACC_PUBLIC = 0x1;
60   private static final int ACC_PRIVATE = 0x2;
61   private static final int ACC_PROTECTED = 0x4;
62
63   private JavaClassGenerator _javaGen = new JavaClassGenerator();
64
65   private JavaClassLoader _jClassLoader;
66   private DynamicClassLoader _loader;
67
68   private Path _workPath;
69
70   private String JavaDoc _baseSuffix = "";
71   private String JavaDoc _extSuffix = "__ResinExt";
72
73   private ArrayList JavaDoc<ClassEnhancer> _enhancerList =
74     new ArrayList JavaDoc<ClassEnhancer>();
75
76   private boolean _isParentStarted;
77
78   /**
79    * Sets the class loader.
80    */

81   public void setClassLoader(DynamicClassLoader loader)
82   {
83     _loader = loader;
84   }
85
86   /**
87    * Returns the parsed class loader.
88    */

89   public void setJavaClassLoader(JavaClassLoader jClassLoader)
90   {
91     _jClassLoader = jClassLoader;
92   }
93
94   /**
95    * Returns the parsed class loader.
96    */

97   public JavaClassLoader getJavaClassLoader()
98   {
99     return _jClassLoader;
100   }
101
102   /**
103    * Gets the work path.
104    */

105   public Path getWorkPath()
106   {
107     if (_workPath != null)
108       return _workPath;
109     else
110       return WorkDir.getLocalWorkDir();
111   }
112
113   /**
114    * Sets the work path.
115    */

116   public void setWorkPath(Path workPath)
117   {
118     _workPath = workPath;
119   }
120
121   /**
122    * Gets the work path.
123    */

124   public final Path getPreWorkPath()
125   {
126     return getWorkPath().lookup("pre-enhance");
127   }
128
129   /**
130    * Gets the work path.
131    */

132   public final Path getPostWorkPath()
133   {
134     return getWorkPath().lookup("post-enhance");
135   }
136
137   /**
138    * Adds a class enhancer.
139    */

140   public void addEnhancer(ClassEnhancer enhancer)
141   {
142     _enhancerList.add(enhancer);
143   }
144
145   protected void fixup(String JavaDoc className, String JavaDoc extClassName)
146     throws Exception JavaDoc
147   {
148     Path prePath = getPreWorkPath();
149     Path postPath = getPostWorkPath();
150
151     Path source = getSource(className);
152
153     if (source == null || ! source.canRead())
154       return;
155
156     Path ext = prePath.lookup(extClassName.replace('.', '/') + ".class");
157     Path target = postPath.lookup(className.replace('.', '/') + ".class");
158
159     try {
160       target.getParent().mkdirs();
161     } catch (Throwable JavaDoc e) {
162     }
163
164     if (source != null)
165       mergeClasses(className, target, source, ext);
166     else
167       mergeClasses(className, target, ext);
168
169     int p = className.lastIndexOf('.');
170
171     Path preTargetDir;
172     Path targetDir;
173     String JavaDoc classSuffix;
174     String JavaDoc prefix = "";
175
176     if (p > 0) {
177       prefix = className.substring(0, p).replace('.', '/');
178       preTargetDir = prePath.lookup(prefix);
179       targetDir = postPath.lookup(prefix);
180       classSuffix = className.substring(p + 1);
181     }
182     else {
183       preTargetDir = prePath;
184       targetDir = postPath;
185       classSuffix = className;
186     }
187
188     prefix = prefix.replace('/', '.');
189     if (! prefix.equals(""))
190       prefix = prefix + ".";
191
192     String JavaDoc extSuffix;
193     p = extClassName.lastIndexOf('.');
194     if (p > 0)
195       extSuffix = extClassName.substring(p + 1);
196     else
197       extSuffix = extClassName;
198
199     fixupPreSubClasses(preTargetDir, targetDir,
200                        extSuffix, classSuffix);
201
202     fixupPostSubClasses(targetDir, prefix, classSuffix);
203   }
204
205   private void fixupPreSubClasses(Path preTargetDir, Path targetDir,
206                                   String JavaDoc extSuffix, String JavaDoc classSuffix)
207     throws Exception JavaDoc
208   {
209     String JavaDoc []list = preTargetDir.list();
210
211     for (int i = 0; i < list.length; i++) {
212       String JavaDoc name = list[i];
213
214       if (name.startsWith(extSuffix + '$') &&
215           name.endsWith(".class")) {
216         int p = name.indexOf('$');
217         String JavaDoc targetClass = (classSuffix + '$' +
218                               name.substring(p + 1, name.length() - 6));
219
220         Path subTarget = targetDir.lookup(targetClass + ".class");
221
222         Path extPath = preTargetDir.lookup(name);
223
224         renameSubClass(classSuffix, subTarget, extPath);
225
226         //if (_loader != null)
227
// _loader.addPathClass(prefix + targetClass, subTarget);
228
}
229       else if (name.startsWith(extSuffix + '-') &&
230                name.endsWith(".class")) {
231         int p = name.indexOf('-');
232         String JavaDoc targetClass = (classSuffix + '-' +
233                               name.substring(p + 1, name.length() - 6));
234
235         Path subTarget = targetDir.lookup(targetClass + ".class");
236
237         Path extPath = preTargetDir.lookup(name);
238
239         renameSubClass(classSuffix, subTarget, extPath);
240
241         //if (_loader != null)
242
// _loader.addPathClass(prefix + targetClass, subTarget);
243
}
244     }
245   }
246
247   private void fixupPostSubClasses(Path targetDir,
248                                    String JavaDoc prefix,
249                                    String JavaDoc classSuffix)
250     throws Exception JavaDoc
251   {
252     String JavaDoc []list = targetDir.list();
253
254     for (int i = 0; i < list.length; i++) {
255       String JavaDoc name = list[i];
256
257       if (! name.endsWith(".class"))
258         continue;
259
260       String JavaDoc className = name.substring(0, name.length() - ".class".length());
261
262       if (name.startsWith(classSuffix + '$')) {
263         if (_loader != null)
264           _loader.addPathClass(prefix + className, targetDir.lookup(name));
265       }
266       else if (name.startsWith(classSuffix + '-')) {
267         if (_loader != null)
268           _loader.addPathClass(prefix + className, targetDir.lookup(name));
269       }
270       else if (name.startsWith(classSuffix + '+')) {
271         if (_loader != null)
272           _loader.addPathClass(prefix + className, targetDir.lookup(name));
273       }
274     }
275   }
276
277   /**
278    * Merges the two classes.
279    */

280   protected void renameSubClass(String JavaDoc className,
281                                 Path targetPath,
282                                 Path extPath)
283     throws Exception JavaDoc
284   {
285     JavaClass extClass = null;
286
287     ByteCodeParser parser = new ByteCodeParser();
288
289     parser = new ByteCodeParser();
290     parser.setClassLoader(new JavaClassLoader());
291
292     ReadStream is = extPath.openRead();
293     try {
294       extClass = parser.parse(is);
295     } finally {
296       if (is != null)
297         is.close();
298     }
299
300     cleanExtConstantPool(className, extClass);
301
302     WriteStream os = targetPath.openWrite();
303     try {
304       extClass.write(os);
305     } finally {
306       os.close();
307     }
308   }
309
310   /**
311    * Renamed the super() methods
312    */

313   protected void renameExtSuperMethods(String JavaDoc className,
314                                        JavaClass baseClass,
315                                        JavaClass extClass)
316     throws Exception JavaDoc
317   {
318     ArrayList JavaDoc<ConstantPoolEntry> entries;
319     entries = extClass.getConstantPool().getEntries();
320
321     className = className.replace('.', '/');
322     String JavaDoc baseName = className + _baseSuffix;
323     String JavaDoc extName = className + "__ResinExt";
324
325     for (int i = 0; i < entries.size(); i++) {
326       ConstantPoolEntry entry = entries.get(i);
327
328       if (entry instanceof MethodRefConstant) {
329         MethodRefConstant methodRef = (MethodRefConstant) entry;
330
331         if (! methodRef.getClassName().equals(baseName))
332           continue;
333
334         String JavaDoc methodName = methodRef.getName();
335         String JavaDoc type = methodRef.getType();
336
337         if (findMethod(baseClass, methodName, type) == null)
338           continue;
339
340         if (findMethod(extClass, methodName, type) == null)
341           continue;
342
343         if (methodName.equals("<init>")) {
344           methodName = "__init__super";
345           // methodRef.setNameAndType(methodName, type);
346
}
347     /* jpa/0h28, shouldn't automatically change this
348         else {
349           methodName = methodName + "__super";
350           methodRef.setNameAndType(methodName, type);
351         }
352     */

353       }
354     }
355   }
356
357
358   /**
359    * Moves all methods in the base to the __super methods
360    */

361   private void moveSuperMethods(String JavaDoc className,
362                                 JavaClass baseClass,
363                                 JavaClass extClass)
364   {
365     className = className.replace('.', '/');
366
367     ArrayList JavaDoc<JavaMethod> methods = baseClass.getMethodList();
368
369     // Move the __super methods
370
ArrayList JavaDoc<JavaMethod> extMethods = extClass.getMethodList();
371     for (int i = 0; i < extMethods.size(); i++) {
372       JavaMethod extMethod = extMethods.get(i);
373
374       fixupExtMethod(baseClass, extClass, extMethod);
375
376       String JavaDoc baseName = extMethod.getName();
377
378       if (baseName.endsWith("__super"))
379         continue;
380
381       String JavaDoc superName = baseName + "__super";
382
383       int j;
384       for (j = 0; j < methods.size(); j++) {
385         JavaMethod method = methods.get(j);
386
387         String JavaDoc type = method.getDescriptor();
388
389         if (! method.getName().equals(baseName) ||
390             ! method.getDescriptor().equals(extMethod.getDescriptor()))
391           continue;
392
393         if (baseName.equals("<init>")) {
394           baseClass.getConstantPool().addUTF8("__init__super");
395           mergeInitMethods(baseClass, method, extClass, extMethod);
396           break;
397         }
398
399         if (baseName.equals("<clinit>")) {
400           concatenateMethods(baseClass, method, extClass, extMethod);
401           break;
402         }
403
404         baseClass.getConstantPool().addUTF8(superName);
405         method.setName(superName);
406         baseClass.getConstantPool().addUTF8(type);
407         method.setDescriptor(type);
408
409         // set the super methods private
410
int flags = method.getAccessFlags();
411         flags = (flags & ~ACC_PUBLIC & ~ACC_PROTECTED) | ACC_PRIVATE;
412         method.setAccessFlags(flags);
413         break;
414       }
415     }
416   }
417
418   /**
419    * Concatenates methods
420    */

421   private void concatenateMethods(JavaClass baseClass, JavaMethod baseMethod,
422                                   JavaClass extClass, JavaMethod extMethod)
423   {
424     extMethod = extMethod.export(extClass, baseClass);
425
426     baseMethod.concatenate(extMethod);
427   }
428
429   /**
430    * Merges the init methods
431    */

432   private void mergeInitMethods(JavaClass baseClass, JavaMethod baseMethod,
433                                 JavaClass extClass, JavaMethod extMethod)
434   {
435     extMethod = extMethod.export(extClass, baseClass);
436
437     baseMethod.setName("__init__super");
438
439     baseClass.getMethodList().add(extMethod);
440
441     try {
442       InitAnalyzer initAnalyzer = new InitAnalyzer();
443       CodeEnhancer baseEnhancer = new CodeEnhancer(baseClass, baseMethod.getCode());
444       baseEnhancer.analyze(initAnalyzer);
445
446       int offset = initAnalyzer.getOffset();
447       byte []code = new byte[offset];
448       byte []oldCode = baseEnhancer.getCode();
449       System.arraycopy(oldCode, 0, code, 0, offset);
450
451       baseEnhancer.remove(0, offset);
452       baseEnhancer.update();
453
454       CodeEnhancer extEnhancer = new CodeEnhancer(baseClass, extMethod.getCode());
455
456       extEnhancer.add(0, code, 0, code.length);
457
458       ExtMethodAnalyzer extMethodAnalyzer
459     = new ExtMethodAnalyzer(baseClass, extMethod, offset);
460       extEnhancer.analyze(extMethodAnalyzer);
461       extEnhancer.update();
462
463       CodeAttribute baseCode = baseMethod.getCode();
464       CodeAttribute extCode = extMethod.getCode();
465
466       if (extCode.getMaxStack() < baseCode.getMaxStack())
467         extCode.setMaxStack(baseCode.getMaxStack());
468
469       // XXX: needs tests badly
470
extCode.removeAttribute("LocalVariableTable");
471       extCode.removeAttribute("LineNumberTable");
472       baseCode.removeAttribute("LocalVariableTable");
473       baseCode.removeAttribute("LineNumberTable");
474
475       /*
476         baseMethod.concatenate(extMethod);
477       */

478     } catch (RuntimeException JavaDoc e) {
479       throw e;
480     } catch (Exception JavaDoc e) {
481       throw new RuntimeException JavaDoc(e);
482     }
483   }
484
485   /**
486    * Merges the init methods
487    */

488   private void fixupExtMethod(JavaClass baseClass,
489                   JavaClass extClass,
490                   JavaMethod extMethod)
491   {
492     try {
493       if (extMethod.getName().endsWith("__super"))
494     return;
495       
496       CodeEnhancer extEnhancer
497     = new CodeEnhancer(extClass, extMethod.getCode());
498
499       ExtMethodAnalyzer extMethodAnalyzer
500     = new ExtMethodAnalyzer(baseClass, extMethod, 0);
501       extEnhancer.analyze(extMethodAnalyzer);
502       extEnhancer.update();
503     } catch (RuntimeException JavaDoc e) {
504       throw e;
505     } catch (Exception JavaDoc e) {
506       throw new RuntimeException JavaDoc(e);
507     }
508   }
509
510   /**
511    * Adds the methods from the ext to the base
512    */

513   private void addExtInterfaces(JavaClass baseClass, JavaClass extClass)
514   {
515     for (String JavaDoc name : extClass.getInterfaceNames()) {
516       baseClass.getConstantPool().addClass(name);
517
518       baseClass.addInterface(name);
519     }
520   }
521
522   /**
523    * Adds the methods from the ext to the base
524    */

525   private void addExtMethods(JavaClass baseClass, JavaClass extClass)
526   {
527     ArrayList JavaDoc<JavaMethod> methods = baseClass.getMethodList();
528     ArrayList JavaDoc<JavaMethod> extMethods = extClass.getMethodList();
529
530     for (int i = 0; i < extMethods.size(); i++) {
531       JavaMethod extMethod = extMethods.get(i);
532
533       if (extMethod.getName().equals("<clinit>") &&
534           findMethod(baseClass, "<clinit>",
535                      extMethod.getDescriptor()) != null) {
536         continue;
537       }
538       else if (extMethod.getName().equals("<init>"))
539         continue;
540       else if (extMethod.getName().endsWith("__super"))
541         continue;
542
543       log.finest("adding extension method: " + extClass.getThisClass() + ":" + extMethod.getName());
544
545       JavaMethod method = extMethod.export(extClass, baseClass);
546
547       methods.add(method);
548     }
549   }
550
551   /**
552    * Adds the inner classes from the ext to the base
553    */

554   private void addExtClasses(JavaClass baseClass, JavaClass extClass)
555   {
556     /*
557       ArrayList<JavaMethod> methods = baseClass.getMethodList();
558       ArrayList<JavaMethod> extMethods = extClass.getMethodList();
559
560       for (int i = 0; i < extMethods.size(); i++) {
561       JavaMethod extMethod = extMethods.get(i);
562
563       if (extMethod.getName().equals("<clinit>") &&
564       findMethod(baseClass, "<clinit>",
565       extMethod.getDescriptor()) != null) {
566       continue;
567       }
568       else if (extMethod.getName().equals("<init>"))
569       continue;
570       else if (extMethod.getName().endsWith("__super"))
571       continue;
572
573       log.finest("adding extension method: " + extClass.getThisClass() + ":" + extMethod.getName());
574
575       JavaMethod method = extMethod.export(extClass, baseClass);
576
577       methods.add(method);
578       }
579     */

580   }
581
582   /**
583    * Finds a matching method.
584    */

585   private static JavaMethod findMethod(JavaClass cl,
586                        String JavaDoc name,
587                        String JavaDoc descriptor)
588   {
589     ArrayList JavaDoc<JavaMethod> methods = cl.getMethodList();
590
591     int j;
592     for (j = 0; j < methods.size(); j++) {
593       JavaMethod method = methods.get(j);
594
595       if (method.getName().equals(name) &&
596           method.getDescriptor().equals(descriptor))
597         return method;
598     }
599
600     return null;
601   }
602
603   /**
604    * Adds all fields from the ext to the base
605    */

606   private void moveSuperFields(JavaClass baseClass, JavaClass extClass)
607   {
608     ArrayList JavaDoc<JavaField> fields = baseClass.getFieldList();
609     ArrayList JavaDoc<JavaField> extFields = extClass.getFieldList();
610
611     for (int i = 0; i < extFields.size(); i++) {
612     }
613   }
614
615   private Path getSource(String JavaDoc className)
616   {
617     ClassLoader JavaDoc loader = _loader;
618     if (loader == null)
619       loader = Thread.currentThread().getContextClassLoader();
620
621     URL JavaDoc url = loader.getResource(className.replace('.', '/') + ".class");
622
623     // XXX: workaround for tck
624
String JavaDoc s = url.toString();
625     int index = s.indexOf("jar!/");
626     if (index > 0) {
627       s = s.substring(9, index+3);
628       Path path = JarPath.create(Vfs.lookup(s));
629       path = path.lookup(className.replace('.', '/') + ".class");
630       return path;
631     }
632
633     return Vfs.lookup(url.toString());
634   }
635
636   /**
637    * Merges the two classes.
638    */

639   protected void mergeClasses(String JavaDoc className,
640                               Path targetPath,
641                               Path sourcePath,
642                               Path extPath)
643     throws Exception JavaDoc
644   {
645     JavaClass baseClass = null;
646     JavaClass extClass = null;
647
648     ByteCodeParser parser = new ByteCodeParser();
649     parser.setClassLoader(getJavaClassLoader());
650
651     ReadStream is = sourcePath.openRead();
652     try {
653       baseClass = parser.parse(is);
654     } finally {
655       if (is != null)
656         is.close();
657     }
658
659     parser = new ByteCodeParser();
660     parser.setClassLoader(getJavaClassLoader());
661
662     is = extPath.openRead();
663     try {
664       extClass = parser.parse(is);
665     } finally {
666       if (is != null)
667         is.close();
668     }
669
670     // jpa/0j26
671
// XXX: later, need to see if it's possible to keep some of this
672
// information for debugging
673
fixupLocalVariableTable(extClass);
674     fixupLocalVariableTable(baseClass);
675     
676     // The base class will have the modified class
677
mergeClasses(className, baseClass, extClass);
678
679     postEnhance(baseClass);
680
681     WriteStream os = targetPath.openWrite();
682     try {
683       baseClass.write(os);
684     } finally {
685       os.close();
686     }
687   }
688
689   /**
690    * Merges the two classes.
691    */

692   protected void mergeClasses(String JavaDoc className,
693                               Path targetPath,
694                               Path extPath)
695     throws Exception JavaDoc
696   {
697     JavaClass baseClass = null;
698     JavaClass extClass = null;
699
700     ByteCodeParser parser = new ByteCodeParser();
701     parser.setClassLoader(getJavaClassLoader());
702
703     ReadStream is = extPath.openRead();
704     try {
705       extClass = parser.parse(is);
706     } finally {
707       if (is != null)
708         is.close();
709     }
710
711     cleanExtConstantPool(className, extClass);
712
713     postEnhance(baseClass);
714
715     WriteStream os = targetPath.openWrite();
716     try {
717       extClass.write(os);
718     } finally {
719       os.close();
720     }
721   }
722
723   /**
724    * After enhancement fixup.
725    */

726   protected void postEnhance(JavaClass baseClass)
727     throws Exception JavaDoc
728   {
729     for (int i = 0; i < _enhancerList.size(); i++) {
730       _enhancerList.get(i).postEnhance(baseClass);
731     }
732
733     fixupJdk16Methods(baseClass);
734   }
735
736   /**
737    * Merges the two classes.
738    */

739   protected void mergeClasses(String JavaDoc className,
740                               JavaClass baseClass,
741                               JavaClass extClass)
742     throws Exception JavaDoc
743   {
744     if (baseClass.getMajor() < extClass.getMajor()) {
745       baseClass.setMajor(extClass.getMajor());
746       baseClass.setMinor(extClass.getMinor());
747     }
748
749     cleanExtConstantPool(className, extClass);
750     renameExtSuperMethods(className, baseClass, extClass);
751
752     cleanExtConstantPool(className, baseClass);
753
754     addExtInterfaces(baseClass, extClass);
755
756     addExtFields(baseClass, extClass);
757
758     moveSuperMethods(className, baseClass, extClass);
759
760     addExtMethods(baseClass, extClass);
761
762     copyExtAnnotations(baseClass);
763
764     addExtClasses(baseClass, extClass);
765   }
766
767   /**
768    * Cleans the ext constant pool, renaming
769    */

770   protected void cleanExtConstantPool(String JavaDoc className, JavaClass extClass)
771     throws Exception JavaDoc
772   {
773     extClass.setThisClass(replaceString(className, extClass.getThisClass()));
774     extClass.setSuperClass(replaceString(className, extClass.getSuperClassName()));
775
776     ArrayList JavaDoc<ConstantPoolEntry> entries;
777     entries = extClass.getConstantPool().getEntries();
778
779     int t = className.lastIndexOf('.');
780     if (t > 0)
781       className = className.substring(t + 1);
782
783     String JavaDoc baseName = className + _baseSuffix;
784     String JavaDoc extName = className + "__ResinExt";
785
786     for (int i = 0; i < entries.size(); i++) {
787       ConstantPoolEntry entry = entries.get(i);
788
789       if (entry instanceof Utf8Constant) {
790         Utf8Constant utf8 = (Utf8Constant) entry;
791
792         String JavaDoc string = utf8.getValue();
793
794         string = replaceString(className, string);
795
796         utf8.setValue(string);
797       }
798     }
799
800     ArrayList JavaDoc<JavaField> fields = extClass.getFieldList();
801     for (int i = 0; i < fields.size(); i++) {
802       JavaField field = fields.get(i);
803
804       field.setName(replaceString(className, field.getName()));
805       field.setDescriptor(replaceString(className, field.getDescriptor()));
806     }
807
808     ArrayList JavaDoc<JavaMethod> methods = extClass.getMethodList();
809     for (int i = 0; i < methods.size(); i++) {
810       JavaMethod method = methods.get(i);
811
812       method.setName(replaceString(className, method.getName()));
813       method.setDescriptor(replaceString(className, method.getDescriptor()));
814     }
815   }
816
817   /**
818    * Adds the methods from the ext to the base
819    */

820   private void copyExtAnnotations(JavaClass baseClass)
821   {
822     for (JavaMethod method : baseClass.getMethodList()) {
823       if (method.getName().endsWith("__super")) {
824         Attribute ann = method.getAttribute("RuntimeVisibleAnnotations");
825
826         if (ann != null) {
827           String JavaDoc name = method.getName();
828           name = name.substring(0, name.length() - "__super".length());
829
830           JavaMethod baseMethod;
831           baseMethod = findMethod(baseClass, name, method.getDescriptor());
832
833           if (baseMethod != null)
834             baseMethod.addAttribute(ann);
835         }
836       }
837     }
838   }
839
840   /**
841    * Adds the methods from the ext to the base
842    */

843   private void addExtFields(JavaClass baseClass, JavaClass extClass)
844   {
845     ArrayList JavaDoc<JavaField> fields = baseClass.getFieldList();
846
847     for (JavaField extField : extClass.getFieldList()) {
848       JavaField field = extField.export(extClass, baseClass);
849
850       if (! fields.contains(field))
851         fields.add(field);
852     }
853   }
854
855   /**
856    * Remove the StackMapTable
857    */

858   private void fixupJdk16Methods(JavaClass baseClass)
859   {
860     for (JavaMethod method : baseClass.getMethodList()) {
861       CodeAttribute code = method.getCode();
862
863       code.removeAttribute("StackMapTable");
864     }
865   }
866
867   /**
868    * Remove the LocalVariableTable
869    */

870   private void fixupLocalVariableTable(JavaClass extClass)
871   {
872     for (JavaMethod method : extClass.getMethodList()) {
873       CodeAttribute code = method.getCode();
874
875       code.removeAttribute("LocalVariableTable");
876       code.removeAttribute("LocalVariableTypeTable");
877     }
878   }
879
880   private String JavaDoc replaceString(String JavaDoc className, String JavaDoc string)
881   {
882     string = replaceStringInt(className.replace('.', '/'), string);
883     string = replaceStringInt(className.replace('.', '$'), string);
884     string = replaceStringInt(className.replace('.', '-'), string);
885
886     return string;
887   }
888
889   private String JavaDoc replaceStringInt(String JavaDoc className, String JavaDoc string)
890   {
891     int t = className.lastIndexOf('.');
892     if (t > 0)
893       className = className.substring(t + 1);
894
895     String JavaDoc baseName = className + _baseSuffix;
896     // String extName = className + "__ResinExt";
897
String JavaDoc extName = "__ResinExt";
898
899     int p;
900     if (! baseName.equals(className)) {
901       while ((p = string.indexOf(baseName)) >= 0) {
902         String JavaDoc prefix = string.substring(0, p);
903         String JavaDoc suffix = string.substring(p + baseName.length());
904
905         string = prefix + className + suffix;
906       }
907     }
908
909     while ((p = string.indexOf(extName)) >= 0) {
910       String JavaDoc prefix = string.substring(0, p);
911       String JavaDoc suffix = string.substring(p + extName.length());
912
913       // string = prefix + className + suffix;
914
string = prefix + suffix;
915     }
916
917     return string;
918   }
919
920   private static class InitAnalyzer extends Analyzer {
921     int _offset = -1;
922
923     /**
924      * Returns the analyzed offset.
925      */

926     public int getOffset()
927     {
928       return _offset;
929     }
930
931     /**
932      * Analyzes the opcode.
933      */

934     public void analyze(CodeVisitor visitor)
935       throws Exception JavaDoc
936     {
937       if (_offset >= 0)
938         return;
939
940       switch (visitor.getOpcode()) {
941       case CodeVisitor.INVOKESPECIAL:
942         JavaClass javaClass = visitor.getJavaClass();
943         ConstantPool cp = javaClass.getConstantPool();
944         MethodRefConstant ref = cp.getMethodRef(visitor.getShortArg());
945
946         // ejb/0l00
947
// handler "super()" and "this()"
948
if (ref.getName().equals("<init>")
949         && (ref.getClassName().equals(javaClass.getThisClass())
950         || ref.getClassName().equals(javaClass.getSuperClassName()))) {
951           _offset = visitor.getOffset() + 3;
952         }
953         break;
954       }
955     }
956   }
957
958   //
959
// convert super.foo() calls to foo__super() where appropriate
960
//
961
private static class ExtMethodAnalyzer extends Analyzer {
962     JClass _baseClass;
963     JMethod _method;
964     int _startOffset;
965     boolean _isEnhanced;
966
967     ExtMethodAnalyzer(JClass baseClass, JMethod method, int length)
968     {
969       _baseClass = baseClass;
970       _method = method;
971       _startOffset = length;
972     }
973
974     /**
975      * Analyzes the opcode.
976      */

977     public void analyze(CodeVisitor visitor)
978       throws Exception JavaDoc
979     {
980       if (_isEnhanced)
981         return;
982
983       if (visitor.getOffset() < _startOffset)
984         return;
985
986       switch (visitor.getOpcode()) {
987       case CodeVisitor.INVOKESPECIAL:
988         int index = visitor.getShortArg();
989
990     JavaClass jClass = visitor.getJavaClass();
991         ConstantPool cp = jClass.getConstantPool();
992         MethodRefConstant ref;
993         ref = cp.getMethodRef(index);
994
995     if (ref.getName().endsWith("__super")) {
996       return;
997     }
998     else if (ref.getName().equals("<init>")
999          && (! ref.getClassName().equals(jClass.getSuperClassName())
1000             || ! _method.getName().equals("<init>"))) {
1001      return;
1002    }
1003    else if (! ref.getName().equals("<init>")) {
1004      // private methods are called with invokespecial, but shouldn't
1005
// be modified
1006
JMethod method = findMethod(jClass,
1007                      ref.getName(),
1008                      ref.getType());
1009
1010      if (method != null && method.isPrivate())
1011        return;
1012    }
1013
1014    String JavaDoc superName;
1015        if (ref.getName().equals("<init>"))
1016      superName = "__init__super";
1017    else
1018      superName = ref.getName() + "__super";
1019
1020        MethodRefConstant newRef;
1021        newRef = cp.addMethodRef(ref.getClassName(),
1022                                 superName,
1023                                 ref.getType());
1024
1025        visitor.setShortArg(1, newRef.getIndex());
1026
1027        _isEnhanced = true;
1028        break;
1029      }
1030    }
1031  }
1032}
1033
Popular Tags