001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.loader.enhancer;
031:
032: import com.caucho.bytecode.*;
033: import com.caucho.java.WorkDir;
034: import com.caucho.java.gen.JavaClassGenerator;
035: import com.caucho.loader.DynamicClassLoader;
036: import com.caucho.util.L10N;
037: import com.caucho.vfs.JarPath;
038: import com.caucho.vfs.Path;
039: import com.caucho.vfs.ReadStream;
040: import com.caucho.vfs.Vfs;
041: import com.caucho.vfs.WriteStream;
042:
043: import java.net.URL;
044: import java.util.ArrayList;
045: import java.util.logging.Logger;
046:
047: /**
048: * Class loader which checks for changes in class files and automatically
049: * picks up new jars.
050: *
051: * <p>DynamicClassLoaders can be chained creating one virtual class loader.
052: * From the perspective of the JDK, it's all one classloader. Internally,
053: * the class loader chain searches like a classpath.
054: */
055: public class EnhancerFixup {
056: private static final L10N L = new L10N(EnhancerFixup.class);
057: private static final Logger log = Logger
058: .getLogger(EnhancerFixup.class.getName());
059:
060: private static final int ACC_PUBLIC = 0x1;
061: private static final int ACC_PRIVATE = 0x2;
062: private static final int ACC_PROTECTED = 0x4;
063:
064: private JavaClassGenerator _javaGen = new JavaClassGenerator();
065:
066: private JavaClassLoader _jClassLoader;
067: private DynamicClassLoader _loader;
068:
069: private Path _workPath;
070:
071: private String _baseSuffix = "";
072: private String _extSuffix = "__ResinExt";
073:
074: private ArrayList<ClassEnhancer> _enhancerList = new ArrayList<ClassEnhancer>();
075:
076: private boolean _isParentStarted;
077:
078: /**
079: * Sets the class loader.
080: */
081: public void setClassLoader(DynamicClassLoader loader) {
082: _loader = loader;
083: }
084:
085: /**
086: * Returns the parsed class loader.
087: */
088: public void setJavaClassLoader(JavaClassLoader jClassLoader) {
089: _jClassLoader = jClassLoader;
090: }
091:
092: /**
093: * Returns the parsed class loader.
094: */
095: public JavaClassLoader getJavaClassLoader() {
096: return _jClassLoader;
097: }
098:
099: /**
100: * Gets the work path.
101: */
102: public Path getWorkPath() {
103: if (_workPath != null)
104: return _workPath;
105: else
106: return WorkDir.getLocalWorkDir();
107: }
108:
109: /**
110: * Sets the work path.
111: */
112: public void setWorkPath(Path workPath) {
113: _workPath = workPath;
114: }
115:
116: /**
117: * Gets the work path.
118: */
119: public final Path getPreWorkPath() {
120: return getWorkPath().lookup("pre-enhance");
121: }
122:
123: /**
124: * Gets the work path.
125: */
126: public final Path getPostWorkPath() {
127: return getWorkPath().lookup("post-enhance");
128: }
129:
130: /**
131: * Adds a class enhancer.
132: */
133: public void addEnhancer(ClassEnhancer enhancer) {
134: _enhancerList.add(enhancer);
135: }
136:
137: protected void fixup(String className, String extClassName)
138: throws Exception {
139: Path prePath = getPreWorkPath();
140: Path postPath = getPostWorkPath();
141:
142: Path source = getSource(className);
143:
144: if (source == null || !source.canRead())
145: return;
146:
147: Path ext = prePath.lookup(extClassName.replace('.', '/')
148: + ".class");
149: Path target = postPath.lookup(className.replace('.', '/')
150: + ".class");
151:
152: try {
153: target.getParent().mkdirs();
154: } catch (Throwable e) {
155: }
156:
157: if (source != null)
158: mergeClasses(className, target, source, ext);
159: else
160: mergeClasses(className, target, ext);
161:
162: int p = className.lastIndexOf('.');
163:
164: Path preTargetDir;
165: Path targetDir;
166: String classSuffix;
167: String prefix = "";
168:
169: if (p > 0) {
170: prefix = className.substring(0, p).replace('.', '/');
171: preTargetDir = prePath.lookup(prefix);
172: targetDir = postPath.lookup(prefix);
173: classSuffix = className.substring(p + 1);
174: } else {
175: preTargetDir = prePath;
176: targetDir = postPath;
177: classSuffix = className;
178: }
179:
180: prefix = prefix.replace('/', '.');
181: if (!prefix.equals(""))
182: prefix = prefix + ".";
183:
184: String extSuffix;
185: p = extClassName.lastIndexOf('.');
186: if (p > 0)
187: extSuffix = extClassName.substring(p + 1);
188: else
189: extSuffix = extClassName;
190:
191: fixupPreSubClasses(preTargetDir, targetDir, extSuffix,
192: classSuffix);
193:
194: fixupPostSubClasses(targetDir, prefix, classSuffix);
195: }
196:
197: private void fixupPreSubClasses(Path preTargetDir, Path targetDir,
198: String extSuffix, String classSuffix) throws Exception {
199: String[] list = preTargetDir.list();
200:
201: for (int i = 0; i < list.length; i++) {
202: String name = list[i];
203:
204: if (name.startsWith(extSuffix + '$')
205: && name.endsWith(".class")) {
206: int p = name.indexOf('$');
207: String targetClass = (classSuffix + '$' + name
208: .substring(p + 1, name.length() - 6));
209:
210: Path subTarget = targetDir.lookup(targetClass
211: + ".class");
212:
213: Path extPath = preTargetDir.lookup(name);
214:
215: renameSubClass(classSuffix, subTarget, extPath);
216:
217: //if (_loader != null)
218: // _loader.addPathClass(prefix + targetClass, subTarget);
219: } else if (name.startsWith(extSuffix + '-')
220: && name.endsWith(".class")) {
221: int p = name.indexOf('-');
222: String targetClass = (classSuffix + '-' + name
223: .substring(p + 1, name.length() - 6));
224:
225: Path subTarget = targetDir.lookup(targetClass
226: + ".class");
227:
228: Path extPath = preTargetDir.lookup(name);
229:
230: renameSubClass(classSuffix, subTarget, extPath);
231:
232: //if (_loader != null)
233: // _loader.addPathClass(prefix + targetClass, subTarget);
234: }
235: }
236: }
237:
238: private void fixupPostSubClasses(Path targetDir, String prefix,
239: String classSuffix) throws Exception {
240: String[] list = targetDir.list();
241:
242: for (int i = 0; i < list.length; i++) {
243: String name = list[i];
244:
245: if (!name.endsWith(".class"))
246: continue;
247:
248: String className = name.substring(0, name.length()
249: - ".class".length());
250:
251: if (name.startsWith(classSuffix + '$')) {
252: if (_loader != null)
253: _loader.addPathClass(prefix + className, targetDir
254: .lookup(name));
255: } else if (name.startsWith(classSuffix + '-')) {
256: if (_loader != null)
257: _loader.addPathClass(prefix + className, targetDir
258: .lookup(name));
259: } else if (name.startsWith(classSuffix + '+')) {
260: if (_loader != null)
261: _loader.addPathClass(prefix + className, targetDir
262: .lookup(name));
263: }
264: }
265: }
266:
267: /**
268: * Merges the two classes.
269: */
270: protected void renameSubClass(String className, Path targetPath,
271: Path extPath) throws Exception {
272: JavaClass extClass = null;
273:
274: ByteCodeParser parser = new ByteCodeParser();
275:
276: parser = new ByteCodeParser();
277: parser.setClassLoader(new JavaClassLoader());
278:
279: ReadStream is = extPath.openRead();
280: try {
281: extClass = parser.parse(is);
282: } finally {
283: if (is != null)
284: is.close();
285: }
286:
287: cleanExtConstantPool(className, extClass);
288:
289: WriteStream os = targetPath.openWrite();
290: try {
291: extClass.write(os);
292: } finally {
293: os.close();
294: }
295: }
296:
297: /**
298: * Renamed the super() methods
299: */
300: protected void renameExtSuperMethods(String className,
301: JavaClass baseClass, JavaClass extClass) throws Exception {
302: ArrayList<ConstantPoolEntry> entries;
303: entries = extClass.getConstantPool().getEntries();
304:
305: className = className.replace('.', '/');
306: String baseName = className + _baseSuffix;
307: String extName = className + "__ResinExt";
308:
309: for (int i = 0; i < entries.size(); i++) {
310: ConstantPoolEntry entry = entries.get(i);
311:
312: if (entry instanceof MethodRefConstant) {
313: MethodRefConstant methodRef = (MethodRefConstant) entry;
314:
315: if (!methodRef.getClassName().equals(baseName))
316: continue;
317:
318: String methodName = methodRef.getName();
319: String type = methodRef.getType();
320:
321: if (findMethod(baseClass, methodName, type) == null)
322: continue;
323:
324: if (findMethod(extClass, methodName, type) == null)
325: continue;
326:
327: if (methodName.equals("<init>")) {
328: methodName = "__init__super";
329: // methodRef.setNameAndType(methodName, type);
330: }
331: /* jpa/0h28, shouldn't automatically change this
332: else {
333: methodName = methodName + "__super";
334: methodRef.setNameAndType(methodName, type);
335: }
336: */
337: }
338: }
339: }
340:
341: /**
342: * Moves all methods in the base to the __super methods
343: */
344: private void moveSuperMethods(String className,
345: JavaClass baseClass, JavaClass extClass) {
346: className = className.replace('.', '/');
347:
348: ArrayList<JavaMethod> methods = baseClass.getMethodList();
349:
350: // Move the __super methods
351: ArrayList<JavaMethod> extMethods = extClass.getMethodList();
352: for (int i = 0; i < extMethods.size(); i++) {
353: JavaMethod extMethod = extMethods.get(i);
354:
355: fixupExtMethod(baseClass, extClass, extMethod);
356:
357: String baseName = extMethod.getName();
358:
359: if (baseName.endsWith("__super"))
360: continue;
361:
362: String super Name = baseName + "__super";
363:
364: int j;
365: for (j = 0; j < methods.size(); j++) {
366: JavaMethod method = methods.get(j);
367:
368: String type = method.getDescriptor();
369:
370: if (!method.getName().equals(baseName)
371: || !method.getDescriptor().equals(
372: extMethod.getDescriptor()))
373: continue;
374:
375: if (baseName.equals("<init>")) {
376: baseClass.getConstantPool()
377: .addUTF8("__init__super");
378: mergeInitMethods(baseClass, method, extClass,
379: extMethod);
380: break;
381: }
382:
383: if (baseName.equals("<clinit>")) {
384: concatenateMethods(baseClass, method, extClass,
385: extMethod);
386: break;
387: }
388:
389: baseClass.getConstantPool().addUTF8(super Name);
390: method.setName(super Name);
391: baseClass.getConstantPool().addUTF8(type);
392: method.setDescriptor(type);
393:
394: // set the super methods private
395: int flags = method.getAccessFlags();
396: flags = (flags & ~ACC_PUBLIC & ~ACC_PROTECTED)
397: | ACC_PRIVATE;
398: method.setAccessFlags(flags);
399: break;
400: }
401: }
402: }
403:
404: /**
405: * Concatenates methods
406: */
407: private void concatenateMethods(JavaClass baseClass,
408: JavaMethod baseMethod, JavaClass extClass,
409: JavaMethod extMethod) {
410: extMethod = extMethod.export(extClass, baseClass);
411:
412: baseMethod.concatenate(extMethod);
413: }
414:
415: /**
416: * Merges the init methods
417: */
418: private void mergeInitMethods(JavaClass baseClass,
419: JavaMethod baseMethod, JavaClass extClass,
420: JavaMethod extMethod) {
421: extMethod = extMethod.export(extClass, baseClass);
422:
423: baseMethod.setName("__init__super");
424:
425: baseClass.getMethodList().add(extMethod);
426:
427: try {
428: InitAnalyzer initAnalyzer = new InitAnalyzer();
429: CodeEnhancer baseEnhancer = new CodeEnhancer(baseClass,
430: baseMethod.getCode());
431: baseEnhancer.analyze(initAnalyzer);
432:
433: int offset = initAnalyzer.getOffset();
434: byte[] code = new byte[offset];
435: byte[] oldCode = baseEnhancer.getCode();
436: System.arraycopy(oldCode, 0, code, 0, offset);
437:
438: baseEnhancer.remove(0, offset);
439: baseEnhancer.update();
440:
441: CodeEnhancer extEnhancer = new CodeEnhancer(baseClass,
442: extMethod.getCode());
443:
444: extEnhancer.add(0, code, 0, code.length);
445:
446: ExtMethodAnalyzer extMethodAnalyzer = new ExtMethodAnalyzer(
447: baseClass, extMethod, offset);
448: extEnhancer.analyze(extMethodAnalyzer);
449: extEnhancer.update();
450:
451: CodeAttribute baseCode = baseMethod.getCode();
452: CodeAttribute extCode = extMethod.getCode();
453:
454: if (extCode.getMaxStack() < baseCode.getMaxStack())
455: extCode.setMaxStack(baseCode.getMaxStack());
456:
457: // XXX: needs tests badly
458: extCode.removeAttribute("LocalVariableTable");
459: extCode.removeAttribute("LineNumberTable");
460: baseCode.removeAttribute("LocalVariableTable");
461: baseCode.removeAttribute("LineNumberTable");
462:
463: /*
464: baseMethod.concatenate(extMethod);
465: */
466: } catch (RuntimeException e) {
467: throw e;
468: } catch (Exception e) {
469: throw new RuntimeException(e);
470: }
471: }
472:
473: /**
474: * Merges the init methods
475: */
476: private void fixupExtMethod(JavaClass baseClass,
477: JavaClass extClass, JavaMethod extMethod) {
478: try {
479: if (extMethod.getName().endsWith("__super"))
480: return;
481:
482: CodeEnhancer extEnhancer = new CodeEnhancer(extClass,
483: extMethod.getCode());
484:
485: ExtMethodAnalyzer extMethodAnalyzer = new ExtMethodAnalyzer(
486: baseClass, extMethod, 0);
487: extEnhancer.analyze(extMethodAnalyzer);
488: extEnhancer.update();
489: } catch (RuntimeException e) {
490: throw e;
491: } catch (Exception e) {
492: throw new RuntimeException(e);
493: }
494: }
495:
496: /**
497: * Adds the methods from the ext to the base
498: */
499: private void addExtInterfaces(JavaClass baseClass,
500: JavaClass extClass) {
501: for (String name : extClass.getInterfaceNames()) {
502: baseClass.getConstantPool().addClass(name);
503:
504: baseClass.addInterface(name);
505: }
506: }
507:
508: /**
509: * Adds the methods from the ext to the base
510: */
511: private void addExtMethods(JavaClass baseClass, JavaClass extClass) {
512: ArrayList<JavaMethod> methods = baseClass.getMethodList();
513: ArrayList<JavaMethod> extMethods = extClass.getMethodList();
514:
515: for (int i = 0; i < extMethods.size(); i++) {
516: JavaMethod extMethod = extMethods.get(i);
517:
518: if (extMethod.getName().equals("<clinit>")
519: && findMethod(baseClass, "<clinit>", extMethod
520: .getDescriptor()) != null) {
521: continue;
522: } else if (extMethod.getName().equals("<init>"))
523: continue;
524: else if (extMethod.getName().endsWith("__super"))
525: continue;
526:
527: log.finest("adding extension method: "
528: + extClass.getThisClass() + ":"
529: + extMethod.getName());
530:
531: JavaMethod method = extMethod.export(extClass, baseClass);
532:
533: methods.add(method);
534: }
535: }
536:
537: /**
538: * Adds the inner classes from the ext to the base
539: */
540: private void addExtClasses(JavaClass baseClass, JavaClass extClass) {
541: /*
542: ArrayList<JavaMethod> methods = baseClass.getMethodList();
543: ArrayList<JavaMethod> extMethods = extClass.getMethodList();
544:
545: for (int i = 0; i < extMethods.size(); i++) {
546: JavaMethod extMethod = extMethods.get(i);
547:
548: if (extMethod.getName().equals("<clinit>") &&
549: findMethod(baseClass, "<clinit>",
550: extMethod.getDescriptor()) != null) {
551: continue;
552: }
553: else if (extMethod.getName().equals("<init>"))
554: continue;
555: else if (extMethod.getName().endsWith("__super"))
556: continue;
557:
558: log.finest("adding extension method: " + extClass.getThisClass() + ":" + extMethod.getName());
559:
560: JavaMethod method = extMethod.export(extClass, baseClass);
561:
562: methods.add(method);
563: }
564: */
565: }
566:
567: /**
568: * Finds a matching method.
569: */
570: private static JavaMethod findMethod(JavaClass cl, String name,
571: String descriptor) {
572: ArrayList<JavaMethod> methods = cl.getMethodList();
573:
574: int j;
575: for (j = 0; j < methods.size(); j++) {
576: JavaMethod method = methods.get(j);
577:
578: if (method.getName().equals(name)
579: && method.getDescriptor().equals(descriptor))
580: return method;
581: }
582:
583: return null;
584: }
585:
586: /**
587: * Adds all fields from the ext to the base
588: */
589: private void moveSuperFields(JavaClass baseClass, JavaClass extClass) {
590: ArrayList<JavaField> fields = baseClass.getFieldList();
591: ArrayList<JavaField> extFields = extClass.getFieldList();
592:
593: for (int i = 0; i < extFields.size(); i++) {
594: }
595: }
596:
597: private Path getSource(String className) {
598: ClassLoader loader = _loader;
599: if (loader == null)
600: loader = Thread.currentThread().getContextClassLoader();
601:
602: URL url = loader.getResource(className.replace('.', '/')
603: + ".class");
604:
605: // XXX: workaround for tck
606: String s = url.toString();
607: int index = s.indexOf("jar!/");
608: if (index > 0) {
609: s = s.substring(9, index + 3);
610: Path path = JarPath.create(Vfs.lookup(s));
611: path = path.lookup(className.replace('.', '/') + ".class");
612: return path;
613: }
614:
615: return Vfs.lookup(url.toString());
616: }
617:
618: /**
619: * Merges the two classes.
620: */
621: protected void mergeClasses(String className, Path targetPath,
622: Path sourcePath, Path extPath) throws Exception {
623: JavaClass baseClass = null;
624: JavaClass extClass = null;
625:
626: ByteCodeParser parser = new ByteCodeParser();
627: parser.setClassLoader(getJavaClassLoader());
628:
629: ReadStream is = sourcePath.openRead();
630: try {
631: baseClass = parser.parse(is);
632: } finally {
633: if (is != null)
634: is.close();
635: }
636:
637: parser = new ByteCodeParser();
638: parser.setClassLoader(getJavaClassLoader());
639:
640: is = extPath.openRead();
641: try {
642: extClass = parser.parse(is);
643: } finally {
644: if (is != null)
645: is.close();
646: }
647:
648: // jpa/0j26
649: // XXX: later, need to see if it's possible to keep some of this
650: // information for debugging
651: fixupLocalVariableTable(extClass);
652: fixupLocalVariableTable(baseClass);
653:
654: // The base class will have the modified class
655: mergeClasses(className, baseClass, extClass);
656:
657: postEnhance(baseClass);
658:
659: WriteStream os = targetPath.openWrite();
660: try {
661: baseClass.write(os);
662: } finally {
663: os.close();
664: }
665: }
666:
667: /**
668: * Merges the two classes.
669: */
670: protected void mergeClasses(String className, Path targetPath,
671: Path extPath) throws Exception {
672: JavaClass baseClass = null;
673: JavaClass extClass = null;
674:
675: ByteCodeParser parser = new ByteCodeParser();
676: parser.setClassLoader(getJavaClassLoader());
677:
678: ReadStream is = extPath.openRead();
679: try {
680: extClass = parser.parse(is);
681: } finally {
682: if (is != null)
683: is.close();
684: }
685:
686: cleanExtConstantPool(className, extClass);
687:
688: postEnhance(baseClass);
689:
690: WriteStream os = targetPath.openWrite();
691: try {
692: extClass.write(os);
693: } finally {
694: os.close();
695: }
696: }
697:
698: /**
699: * After enhancement fixup.
700: */
701: protected void postEnhance(JavaClass baseClass) throws Exception {
702: for (int i = 0; i < _enhancerList.size(); i++) {
703: _enhancerList.get(i).postEnhance(baseClass);
704: }
705:
706: fixupJdk16Methods(baseClass);
707: }
708:
709: /**
710: * Merges the two classes.
711: */
712: protected void mergeClasses(String className, JavaClass baseClass,
713: JavaClass extClass) throws Exception {
714: if (baseClass.getMajor() < extClass.getMajor()) {
715: baseClass.setMajor(extClass.getMajor());
716: baseClass.setMinor(extClass.getMinor());
717: }
718:
719: cleanExtConstantPool(className, extClass);
720: renameExtSuperMethods(className, baseClass, extClass);
721:
722: cleanExtConstantPool(className, baseClass);
723:
724: addExtInterfaces(baseClass, extClass);
725:
726: addExtFields(baseClass, extClass);
727:
728: moveSuperMethods(className, baseClass, extClass);
729:
730: addExtMethods(baseClass, extClass);
731:
732: copyExtAnnotations(baseClass);
733:
734: addExtClasses(baseClass, extClass);
735: }
736:
737: /**
738: * Cleans the ext constant pool, renaming
739: */
740: protected void cleanExtConstantPool(String className,
741: JavaClass extClass) throws Exception {
742: extClass.setThisClass(replaceString(className, extClass
743: .getThisClass()));
744: extClass.setSuperClass(replaceString(className, extClass
745: .getSuperClassName()));
746:
747: ArrayList<ConstantPoolEntry> entries;
748: entries = extClass.getConstantPool().getEntries();
749:
750: int t = className.lastIndexOf('.');
751: if (t > 0)
752: className = className.substring(t + 1);
753:
754: String baseName = className + _baseSuffix;
755: String extName = className + "__ResinExt";
756:
757: for (int i = 0; i < entries.size(); i++) {
758: ConstantPoolEntry entry = entries.get(i);
759:
760: if (entry instanceof Utf8Constant) {
761: Utf8Constant utf8 = (Utf8Constant) entry;
762:
763: String string = utf8.getValue();
764:
765: string = replaceString(className, string);
766:
767: utf8.setValue(string);
768: }
769: }
770:
771: ArrayList<JavaField> fields = extClass.getFieldList();
772: for (int i = 0; i < fields.size(); i++) {
773: JavaField field = fields.get(i);
774:
775: field.setName(replaceString(className, field.getName()));
776: field.setDescriptor(replaceString(className, field
777: .getDescriptor()));
778: }
779:
780: ArrayList<JavaMethod> methods = extClass.getMethodList();
781: for (int i = 0; i < methods.size(); i++) {
782: JavaMethod method = methods.get(i);
783:
784: method.setName(replaceString(className, method.getName()));
785: method.setDescriptor(replaceString(className, method
786: .getDescriptor()));
787: }
788: }
789:
790: /**
791: * Adds the methods from the ext to the base
792: */
793: private void copyExtAnnotations(JavaClass baseClass) {
794: for (JavaMethod method : baseClass.getMethodList()) {
795: if (method.getName().endsWith("__super")) {
796: Attribute ann = method
797: .getAttribute("RuntimeVisibleAnnotations");
798:
799: if (ann != null) {
800: String name = method.getName();
801: name = name.substring(0, name.length()
802: - "__super".length());
803:
804: JavaMethod baseMethod;
805: baseMethod = findMethod(baseClass, name, method
806: .getDescriptor());
807:
808: if (baseMethod != null)
809: baseMethod.addAttribute(ann);
810: }
811: }
812: }
813: }
814:
815: /**
816: * Adds the methods from the ext to the base
817: */
818: private void addExtFields(JavaClass baseClass, JavaClass extClass) {
819: ArrayList<JavaField> fields = baseClass.getFieldList();
820:
821: for (JavaField extField : extClass.getFieldList()) {
822: JavaField field = extField.export(extClass, baseClass);
823:
824: if (!fields.contains(field))
825: fields.add(field);
826: }
827: }
828:
829: /**
830: * Remove the StackMapTable
831: */
832: private void fixupJdk16Methods(JavaClass baseClass) {
833: for (JavaMethod method : baseClass.getMethodList()) {
834: CodeAttribute code = method.getCode();
835:
836: code.removeAttribute("StackMapTable");
837: }
838: }
839:
840: /**
841: * Remove the LocalVariableTable
842: */
843: private void fixupLocalVariableTable(JavaClass extClass) {
844: for (JavaMethod method : extClass.getMethodList()) {
845: CodeAttribute code = method.getCode();
846:
847: code.removeAttribute("LocalVariableTable");
848: code.removeAttribute("LocalVariableTypeTable");
849: }
850: }
851:
852: private String replaceString(String className, String string) {
853: string = replaceStringInt(className.replace('.', '/'), string);
854: string = replaceStringInt(className.replace('.', '$'), string);
855: string = replaceStringInt(className.replace('.', '-'), string);
856:
857: return string;
858: }
859:
860: private String replaceStringInt(String className, String string) {
861: int t = className.lastIndexOf('.');
862: if (t > 0)
863: className = className.substring(t + 1);
864:
865: String baseName = className + _baseSuffix;
866: // String extName = className + "__ResinExt";
867: String extName = "__ResinExt";
868:
869: int p;
870: if (!baseName.equals(className)) {
871: while ((p = string.indexOf(baseName)) >= 0) {
872: String prefix = string.substring(0, p);
873: String suffix = string.substring(p + baseName.length());
874:
875: string = prefix + className + suffix;
876: }
877: }
878:
879: while ((p = string.indexOf(extName)) >= 0) {
880: String prefix = string.substring(0, p);
881: String suffix = string.substring(p + extName.length());
882:
883: // string = prefix + className + suffix;
884: string = prefix + suffix;
885: }
886:
887: return string;
888: }
889:
890: private static class InitAnalyzer extends Analyzer {
891: int _offset = -1;
892:
893: /**
894: * Returns the analyzed offset.
895: */
896: public int getOffset() {
897: return _offset;
898: }
899:
900: /**
901: * Analyzes the opcode.
902: */
903: public void analyze(CodeVisitor visitor) throws Exception {
904: if (_offset >= 0)
905: return;
906:
907: switch (visitor.getOpcode()) {
908: case CodeVisitor.INVOKESPECIAL:
909: JavaClass javaClass = visitor.getJavaClass();
910: ConstantPool cp = javaClass.getConstantPool();
911: MethodRefConstant ref = cp.getMethodRef(visitor
912: .getShortArg());
913:
914: // ejb/0l00
915: // handler "super()" and "this()"
916: if (ref.getName().equals("<init>")
917: && (ref.getClassName().equals(
918: javaClass.getThisClass()) || ref
919: .getClassName().equals(
920: javaClass.getSuperClassName()))) {
921: _offset = visitor.getOffset() + 3;
922: }
923: break;
924: }
925: }
926: }
927:
928: //
929: // convert super.foo() calls to foo__super() where appropriate
930: //
931: private static class ExtMethodAnalyzer extends Analyzer {
932: JClass _baseClass;
933: JMethod _method;
934: int _startOffset;
935: boolean _isEnhanced;
936:
937: ExtMethodAnalyzer(JClass baseClass, JMethod method, int length) {
938: _baseClass = baseClass;
939: _method = method;
940: _startOffset = length;
941: }
942:
943: /**
944: * Analyzes the opcode.
945: */
946: public void analyze(CodeVisitor visitor) throws Exception {
947: if (_isEnhanced)
948: return;
949:
950: if (visitor.getOffset() < _startOffset)
951: return;
952:
953: switch (visitor.getOpcode()) {
954: case CodeVisitor.INVOKESPECIAL:
955: int index = visitor.getShortArg();
956:
957: JavaClass jClass = visitor.getJavaClass();
958: ConstantPool cp = jClass.getConstantPool();
959: MethodRefConstant ref;
960: ref = cp.getMethodRef(index);
961:
962: if (ref.getName().endsWith("__super")) {
963: return;
964: } else if (ref.getName().equals("<init>")
965: && (!ref.getClassName().equals(
966: jClass.getSuperClassName()) || !_method
967: .getName().equals("<init>"))) {
968: return;
969: } else if (!ref.getName().equals("<init>")) {
970: // private methods are called with invokespecial, but shouldn't
971: // be modified
972: JMethod method = findMethod(jClass, ref.getName(),
973: ref.getType());
974:
975: if (method != null && method.isPrivate())
976: return;
977: }
978:
979: String super Name;
980: if (ref.getName().equals("<init>"))
981: super Name = "__init__super";
982: else
983: super Name = ref.getName() + "__super";
984:
985: MethodRefConstant newRef;
986: newRef = cp.addMethodRef(ref.getClassName(), super Name,
987: ref.getType());
988:
989: visitor.setShortArg(1, newRef.getIndex());
990:
991: _isEnhanced = true;
992: break;
993: }
994: }
995: }
996: }
|