001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.commons.jci.compilers;
019:
020: import java.io.File;
021: import java.io.FileInputStream;
022: import java.io.FileOutputStream;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.net.MalformedURLException;
026: import java.net.URL;
027: import java.net.URLClassLoader;
028: import java.util.HashMap;
029: import java.util.Locale;
030: import java.util.Map;
031:
032: import org.objectweb.asm.ClassReader;
033: import org.objectweb.asm.ClassWriter;
034: import org.objectweb.asm.util.CheckClassAdapter;
035: import org.vafer.dependency.asm.RenamingVisitor;
036: import org.vafer.dependency.utils.ResourceRenamer;
037:
038: /**
039: * This classloader injects the FileIn/OutputStream wrappers
040: * into javac. Access to the store/reader is done via ThreadLocals.
041: * It also tries to find the javac class on the system and expands
042: * the classpath accordingly.
043: *
044: * @author tcurdt
045: */
046: public final class JavacClassLoader extends URLClassLoader {
047:
048: private final Map loaded = new HashMap();
049:
050: public JavacClassLoader(final ClassLoader pParent) {
051: super (getToolsJar(), pParent);
052: }
053:
054: private static URL[] getToolsJar() {
055: try {
056: Class.forName("com.sun.tools.javac.Main");
057:
058: // found - no addtional classpath entry required
059: return new URL[0];
060:
061: } catch (Exception e) {
062: }
063:
064: // no compiler in current classpath, let's try to find the tools.jar
065:
066: String javaHome = System.getProperty("java.home");
067: if (javaHome.toLowerCase(Locale.US).endsWith(
068: File.separator + "jre")) {
069: javaHome = javaHome.substring(0, javaHome.length() - 4);
070: }
071:
072: final File toolsJar = new File(javaHome + "/lib/tools.jar");
073:
074: if (toolsJar.exists()) {
075: try {
076: return new URL[] { toolsJar.toURL() };
077: } catch (MalformedURLException e) {
078: }
079: }
080:
081: final StringBuffer sb = new StringBuffer();
082: sb
083: .append("Could not find javac compiler class (should be in the tools.jar/classes.jar in your JRE/JDK). ");
084: sb.append("os.name").append('=').append(
085: System.getProperty("os.name")).append(", ");
086: sb.append("os.version").append('=').append(
087: System.getProperty("os.version")).append(", ");
088: sb.append("java.class.path").append('=').append(
089: System.getProperty("java.class.path"));
090:
091: throw new RuntimeException(sb.toString());
092: }
093:
094: protected Class findClass(final String name)
095: throws ClassNotFoundException {
096:
097: if (name.startsWith("java.")) {
098: return super .findClass(name);
099: }
100:
101: try {
102:
103: final Class clazz = (Class) loaded.get(name);
104: if (clazz != null) {
105: return clazz;
106: }
107:
108: final byte[] classBytes;
109:
110: if (name.startsWith("com.sun.tools.javac.")) {
111: final InputStream classStream = getResourceAsStream(name
112: .replace('.', '/')
113: + ".class");
114:
115: final ClassWriter renamedCw = new ClassWriter(true,
116: false);
117: new ClassReader(classStream).accept(
118: new RenamingVisitor(new CheckClassAdapter(
119: renamedCw), new ResourceRenamer() {
120: public String getNewNameFor(
121: final String pOldName) {
122: if (pOldName
123: .startsWith(FileOutputStream.class
124: .getName())) {
125: return FileOutputStreamProxy.class
126: .getName();
127: }
128: if (pOldName
129: .startsWith(FileInputStream.class
130: .getName())) {
131: return FileInputStreamProxy.class
132: .getName();
133: }
134: return pOldName;
135: }
136: }), false);
137:
138: classBytes = renamedCw.toByteArray();
139:
140: } else {
141: return super .findClass(name);
142: }
143:
144: final Class newClazz = defineClass(name, classBytes, 0,
145: classBytes.length);
146: loaded.put(name, newClazz);
147: return newClazz;
148: } catch (IOException e) {
149: throw new ClassNotFoundException("", e);
150: }
151: }
152:
153: protected synchronized Class loadClass(final String classname,
154: final boolean resolve) throws ClassNotFoundException {
155:
156: Class theClass = findLoadedClass(classname);
157: if (theClass != null) {
158: return theClass;
159: }
160:
161: try {
162: theClass = findClass(classname);
163: } catch (ClassNotFoundException cnfe) {
164: theClass = getParent().loadClass(classname);
165: }
166:
167: if (resolve) {
168: resolveClass(theClass);
169: }
170:
171: return theClass;
172: }
173: }
|