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 java.io.File;
034: import net.sf.retrotranslator.runtime.impl.*;
035:
036: /**
037: * @author Taras Puchko
038: */
039: public class JITRetrotranslator {
040:
041: private boolean advanced;
042: private boolean smart;
043: private String support;
044: private String backport;
045: private ClassTransformer transformer;
046:
047: public JITRetrotranslator() {
048: }
049:
050: public void setAdvanced(boolean advanced) {
051: this .advanced = advanced;
052: }
053:
054: public void setSmart(boolean smart) {
055: this .smart = smart;
056: }
057:
058: public void setSupport(String support) {
059: this .support = support;
060: }
061:
062: public void setBackport(String backport) {
063: this .backport = backport;
064: }
065:
066: public boolean run() {
067: if (isJava5Supported())
068: return true;
069: OperationMode mode = new OperationMode(advanced, support,
070: smart, ClassVersion.VERSION_14);
071: TargetEnvironment environment = new TargetEnvironment(
072: TransformerTools.getDefaultClassLoader(), null, true);
073: ReplacementLocatorFactory factory = new ReplacementLocatorFactory(
074: mode, false, backport, environment);
075: SystemLogger logger = new SystemLogger(new MessageLogger() {
076: public void log(Message message) {
077: //do nothing
078: }
079: }, false);
080: transformer = new ClassTransformer(true, false, false, false,
081: ReflectionMode.NORMAL, logger, null, factory);
082: ClassDescriptor.setBytecodeTransformer(transformer);
083: SunJITRetrotranslator.install(transformer);
084: if (isJava5Supported())
085: return true;
086: JRockitJITRetrotranslator.install(transformer);
087: return isJava5Supported();
088: }
089:
090: private static boolean isJava5Supported() {
091: class ClassFactory extends ClassLoader {
092: public Class defineClass(String name, byte[] bytes) {
093: return defineClass(name, bytes, 0, bytes.length);
094: }
095: }
096: byte[] bytes = RuntimeTools
097: .getBytecode(JITRetrotranslator.class);
098: System.arraycopy(new byte[] { 0, 0, 0, 49 }, 0, bytes, 4, 4);
099: try {
100: new ClassFactory().defineClass(JITRetrotranslator.class
101: .getName(), bytes);
102: return true;
103: } catch (ClassFormatError e) {
104: return false;
105: }
106: }
107:
108: public static void main(String[] args) throws Exception {
109: JITRetrotranslator jit = new JITRetrotranslator();
110: boolean jar = false;
111: int i;
112: for (i = 0; i < args.length; i++) {
113: String option = args[i];
114: if (option.equals("-advanced")) {
115: jit.setAdvanced(true);
116: } else if (option.equals("-smart")) {
117: jit.setSmart(true);
118: } else if (option.equals("-support") && i + 1 < args.length) {
119: jit.setSupport(args[++i]);
120: } else if (option.equals("-backport")
121: && i + 1 < args.length) {
122: jit.setBackport(args[++i]);
123: } else if (option.equals("-jar")) {
124: jar = true;
125: i++;
126: break;
127: } else {
128: break;
129: }
130: }
131: if (i == args.length) {
132: printUsageAndExit();
133: }
134: boolean installed = jit.run();
135: if (jar) {
136: File file = new File(args[i]);
137: if (!file.isFile()) {
138: printErrorAndExit("Unable to access jarfile " + file);
139: }
140: JarClassLoader classLoader = installed ? new JarClassLoader(
141: file, TransformerTools.getDefaultClassLoader())
142: : new TransformingJarClassLoader(file,
143: TransformerTools.getDefaultClassLoader(),
144: jit.transformer);
145: String mainClass = classLoader.getMainClass();
146: if (mainClass == null) {
147: printErrorAndExit("Failed to load Main-Class manifest attribute from "
148: + file);
149: }
150: Thread.currentThread().setContextClassLoader(classLoader);
151: execute(classLoader, mainClass, remove(args, i + 1));
152: } else {
153: if (!installed) {
154: System.out
155: .println("Cannot install Retrotranslator, use -jar.");
156: }
157: execute(TransformerTools.getDefaultClassLoader(), args[i],
158: remove(args, i + 1));
159: }
160: }
161:
162: private static String[] remove(String[] original, int count) {
163: String[] result = new String[original.length - count];
164: System.arraycopy(original, original.length - result.length,
165: result, 0, result.length);
166: return result;
167: }
168:
169: private static void execute(ClassLoader classLoader,
170: String mainClass, String[] args) throws Exception {
171: try {
172: classLoader.loadClass(mainClass).getMethod("main",
173: String[].class).invoke(null, new Object[] { args });
174: } catch (NoSuchMethodException e) {
175: printErrorAndExit("Could not find the method \"main\" in: "
176: + mainClass);
177: } catch (ClassNotFoundException e) {
178: printErrorAndExit("Could not find the main class: "
179: + mainClass);
180: }
181: }
182:
183: private static void printUsageAndExit() {
184: String version = JITRetrotranslator.class.getPackage()
185: .getImplementationVersion();
186: String suffix = (version == null) ? "" : "-" + version;
187: StringBuilder builder = new StringBuilder(
188: "Usage: java -cp retrotranslator-transformer")
189: .append(suffix);
190: builder.append(".jar").append(File.pathSeparator);
191: builder
192: .append("<classpath> net.sf.retrotranslator.transformer.JITRetrotranslator"
193: + " [-advanced] [-support <features>] [-backport <packages>] <class> [<args...>]\n");
194: builder.append(" or java -cp retrotranslator-transformer")
195: .append(suffix);
196: builder
197: .append(".jar net.sf.retrotranslator.transformer.JITRetrotranslator"
198: + " [-advanced] [-support <features>] [-backport <packages>] -jar <jarfile> [<args...>]");
199: System.out.println(builder);
200: System.exit(1);
201: }
202:
203: private static void printErrorAndExit(String msg) {
204: System.out.println(msg);
205: System.exit(1);
206: }
207: }
|