001: /***
002: * Retrotranslator: a Java bytecode transformer that translates Java classes
003: * compiled with JDK 5.0 into classes that can be run on JVM 1.4.
004: *
005: * Copyright (c) 2005 - 2008 Taras Puchko
006: * All rights reserved.
007: *
008: * Redistribution and use in source and binary forms, with or without
009: * modification, are permitted provided that the following conditions
010: * are met:
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * 3. Neither the name of the copyright holders nor the names of its
017: * contributors may be used to endorse or promote products derived from
018: * this software without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
021: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
022: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
023: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
024: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
025: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
026: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
027: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
028: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
029: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
030: * THE POSSIBILITY OF SUCH DAMAGE.
031: */package net.sf.retrotranslator.transformer;
032:
033: import net.sf.retrotranslator.runtime.asm.*;
034: import java.io.*;
035:
036: /**
037: * @author Taras Puchko
038: */
039: public abstract class RuntimeCreator {
040:
041: private static final String SOURCE_PACKAGE = "net/sf/retrotranslator/runtime/";
042:
043: private final File rootFolder;
044: private final String targetPackage;
045: private final String infix;
046: private String className;
047:
048: protected RuntimeCreator(File rootFolder, String targetPackage,
049: String infix) {
050: this .targetPackage = targetPackage;
051: this .rootFolder = rootFolder;
052: this .infix = infix;
053: }
054:
055: protected abstract boolean isRightMethod(String name);
056:
057: protected abstract boolean isRightInnerClass(String innerName);
058:
059: protected boolean isClass(String name) {
060: return className.equals(targetPackage + infix + name);
061: }
062:
063: protected void execute() throws IOException {
064: traverse(new File(rootFolder, targetPackage));
065: traverse(new File(rootFolder, SOURCE_PACKAGE));
066: }
067:
068: private void traverse(File folder) throws IOException {
069: for (File file : folder.listFiles()) {
070: if (file.isDirectory()) {
071: traverse(file);
072: } else if (file.getPath().endsWith(".class")) {
073: copy(file);
074: }
075: }
076: }
077:
078: private void copy(File source) throws IOException {
079: ClassWriter classWriter = new ClassWriter(true);
080: FileInputStream inputStream = new FileInputStream(source);
081: try {
082: new ClassReader(inputStream).accept(
083: new RuntimeCreatorVisitor(classWriter), false);
084: } finally {
085: inputStream.close();
086: }
087: File target = new File(rootFolder, className + ".class");
088: target.getParentFile().mkdirs();
089: FileOutputStream outputStream = new FileOutputStream(target);
090: try {
091: outputStream.write(classWriter.toByteArray(false));
092: } finally {
093: outputStream.close();
094: }
095: }
096:
097: private class RuntimeCreatorVisitor extends GenericClassVisitor {
098:
099: public RuntimeCreatorVisitor(ClassVisitor visitor) {
100: super (visitor);
101: }
102:
103: protected String typeName(String s) {
104: if (s == null || !s.startsWith(SOURCE_PACKAGE)) {
105: return s;
106: }
107: String name = s.substring(SOURCE_PACKAGE.length());
108: StringBuilder builder = new StringBuilder(targetPackage);
109: if (name.startsWith("java")) {
110: builder.append(infix);
111: }
112: return builder.append(name).toString();
113: }
114:
115: public void visit(int version, int access, String name,
116: String signature, String super Name, String[] interfaces) {
117: super .visit(version, access, name, signature, super Name,
118: interfaces);
119: className = typeName(name);
120: }
121:
122: public MethodVisitor visitMethod(int access, String name,
123: String desc, String signature, String[] exceptions) {
124: return isRightMethod(name) ? super .visitMethod(access,
125: name, desc, signature, exceptions) : null;
126: }
127:
128: public void visitInnerClass(String name, String outerName,
129: String innerName, int access) {
130: if (isRightInnerClass(innerName)) {
131: super.visitInnerClass(name, outerName, innerName,
132: access);
133: }
134: }
135: }
136:
137: }
|