001: /*
002: * Janino - An embedded Java[TM] compiler
003: *
004: * Copyright (c) 2001-2007, Arno Unkrig
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
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
014: * copyright notice, this list of conditions and the following
015: * disclaimer in the documentation and/or other materials
016: * provided with the distribution.
017: * 3. The name of the author may not be used to endorse or promote
018: * products derived from this software without specific prior
019: * written permission.
020: *
021: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
022: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
023: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
024: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
025: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
026: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
027: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
028: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
029: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
030: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
031: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
032: */
033:
034: package org.codehaus.janino;
035:
036: import java.io.*;
037: import java.util.*;
038:
039: import org.codehaus.janino.util.*;
040: import org.codehaus.janino.util.resource.*;
041:
042: /**
043: * This {@link org.codehaus.janino.IClassLoader} finds, scans and parses compilation units.
044: * <p>
045: * Notice that it does not compile them!
046: */
047: public final class JavaSourceIClassLoader extends IClassLoader {
048: private static final boolean DEBUG = false;
049:
050: private final ResourceFinder sourceFinder;
051: private final String optionalCharacterEncoding;
052: private final Set unitCompilers; // UnitCompiler
053: private UnitCompiler.ErrorHandler optionalCompileErrorHandler = null;
054: private WarningHandler optionalWarningHandler = null;
055:
056: /**
057: * Notice that the <code>unitCompilers</code> set is both read and written
058: * by the {@link JavaSourceIClassLoader}: As it searches for {@link IClass}es, it looks
059: * into <code>unitCompilers</code> for class declarations, and as it opens,
060: * scans and parses compilation units on-the-fly, it adds them to
061: * <code>unitCompilers</code>.
062: */
063: public JavaSourceIClassLoader(ResourceFinder sourceFinder,
064: String optionalCharacterEncoding, Set unitCompilers, // UnitCompiler
065: IClassLoader optionalParentIClassLoader) {
066: super (optionalParentIClassLoader);
067:
068: this .sourceFinder = sourceFinder;
069: this .optionalCharacterEncoding = optionalCharacterEncoding;
070: this .unitCompilers = unitCompilers;
071: super .postConstruct();
072: }
073:
074: /**
075: * @see UnitCompiler#setCompileErrorHandler(ErrorHandler)
076: */
077: public void setCompileErrorHandler(
078: UnitCompiler.ErrorHandler optionalCompileErrorHandler) {
079: this .optionalCompileErrorHandler = optionalCompileErrorHandler;
080: }
081:
082: /**
083: * @see Parser#setWarningHandler(WarningHandler)
084: * @see UnitCompiler#setCompileErrorHandler(ErrorHandler)
085: */
086: public void setWarningHandler(WarningHandler optionalWarningHandler) {
087: this .optionalWarningHandler = optionalWarningHandler;
088: }
089:
090: /**
091: * @param type field descriptor of the {@link IClass} to load, e.g. "Lpkg1/pkg2/Outer$Inner;"
092: * @throws ClassNotFoundException if an exception was raised while loading the {@link IClass}
093: */
094: public IClass findIClass(final String type)
095: throws ClassNotFoundException {
096: if (JavaSourceIClassLoader.DEBUG)
097: System.out.println("type = " + type);
098:
099: // Class type.
100: String className = Descriptor.toClassName(type); // E.g. "pkg1.pkg2.Outer$Inner"
101: if (JavaSourceIClassLoader.DEBUG)
102: System.out.println("2 className = \"" + className + "\"");
103:
104: // Do not attempt to load classes from package "java".
105: if (className.startsWith("java."))
106: return null;
107:
108: // Determine the name of the top-level class.
109: String topLevelClassName;
110: {
111: int idx = className.indexOf('$');
112: topLevelClassName = idx == -1 ? className : className
113: .substring(0, idx);
114: }
115:
116: // Check the already-parsed compilation units.
117: for (Iterator it = this .unitCompilers.iterator(); it.hasNext();) {
118: UnitCompiler uc = (UnitCompiler) it.next();
119: IClass res = uc.findClass(topLevelClassName);
120: if (res != null) {
121: if (!className.equals(topLevelClassName)) {
122: res = uc.findClass(className);
123: if (res == null)
124: return null;
125: }
126: this .defineIClass(res);
127: return res;
128: }
129: }
130:
131: // Find source file.
132: Resource sourceResource = this .sourceFinder
133: .findResource(ClassFile
134: .getSourceResourceName(className));
135: if (sourceResource == null)
136: return null;
137: if (JavaSourceIClassLoader.DEBUG)
138: System.out.println("sourceURL=" + sourceResource);
139:
140: try {
141:
142: // Scan and parse the source file.
143: InputStream inputStream = sourceResource.open();
144: Java.CompilationUnit cu;
145: try {
146: Scanner scanner = new Scanner(sourceResource
147: .getFileName(), inputStream,
148: this .optionalCharacterEncoding);
149: scanner.setWarningHandler(this .optionalWarningHandler);
150: Parser parser = new Parser(scanner);
151: parser.setWarningHandler(this .optionalWarningHandler);
152: cu = parser.parseCompilationUnit();
153: } finally {
154: try {
155: inputStream.close();
156: } catch (IOException ex) {
157: }
158: }
159: UnitCompiler uc = new UnitCompiler(cu, this );
160: uc.setCompileErrorHandler(this .optionalCompileErrorHandler);
161: uc.setWarningHandler(this .optionalWarningHandler);
162:
163: // Remember compilation unit for later compilation.
164: this .unitCompilers.add(uc);
165:
166: // Find the class/interface declaration in the compiled unit.
167: IClass res = uc.findClass(className);
168: if (res == null) {
169: if (className.equals(topLevelClassName))
170: throw new Parser.ParseException("Source file \""
171: + sourceResource.getFileName()
172: + "\" does not declare class \""
173: + className + "\"", (Location) null);
174: return null;
175: }
176: this .defineIClass(res);
177: return res;
178: } catch (Scanner.ScanException e) {
179: throw new ClassNotFoundException(
180: "Parsing compilation unit \"" + sourceResource
181: + "\"", e);
182: } catch (Parser.ParseException e) {
183: throw new ClassNotFoundException(
184: "Parsing compilation unit \"" + sourceResource
185: + "\"", e);
186: } catch (IOException e) {
187: throw new ClassNotFoundException(
188: "Parsing compilation unit \"" + sourceResource
189: + "\"", e);
190: } catch (CompileException e) {
191: throw new ClassNotFoundException(
192: "Parsing compilation unit \"" + sourceResource
193: + "\"", e);
194: }
195: }
196: }
|