001: /*
002: * Janino - An embedded Java[TM] compiler
003: *
004: * Copyright (c) 2006, 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: 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: // Check the already-parsed compilation units.
109: for (Iterator it = this .unitCompilers.iterator(); it.hasNext();) {
110: UnitCompiler uc = (UnitCompiler) it.next();
111: IClass res = uc.findClass(className);
112: if (res != null) {
113: this .defineIClass(res);
114: return res;
115: }
116: }
117:
118: // Find source file.
119: Resource sourceResource = this .sourceFinder
120: .findResource(ClassFile
121: .getSourceResourceName(className));
122: if (sourceResource == null)
123: return null;
124: if (JavaSourceIClassLoader.DEBUG)
125: System.out.println("sourceURL=" + sourceResource);
126:
127: try {
128:
129: // Scan and parse the source file.
130: InputStream inputStream = sourceResource.open();
131: Java.CompilationUnit cu;
132: try {
133: Scanner scanner = new Scanner(sourceResource
134: .getFileName(), inputStream,
135: this .optionalCharacterEncoding);
136: scanner.setWarningHandler(this .optionalWarningHandler);
137: Parser parser = new Parser(scanner);
138: parser.setWarningHandler(this .optionalWarningHandler);
139: cu = parser.parseCompilationUnit();
140: } finally {
141: try {
142: inputStream.close();
143: } catch (IOException ex) {
144: }
145: }
146: UnitCompiler uc = new UnitCompiler(cu, this );
147: uc.setCompileErrorHandler(this .optionalCompileErrorHandler);
148: uc.setWarningHandler(this .optionalWarningHandler);
149:
150: // Remember compilation unit for later compilation.
151: this .unitCompilers.add(uc);
152:
153: // Find the class/interface declaration in the com
154: IClass res = uc.findClass(className);
155: if (res == null)
156: throw new Parser.ParseException("Source file \""
157: + sourceResource.getFileName()
158: + "\" does not declare class \"" + className
159: + "\"", (Location) null);
160: this .defineIClass(res);
161: return res;
162: } catch (Scanner.ScanException e) {
163: throw new ClassNotFoundException(
164: "Parsing compilation unit \"" + sourceResource
165: + "\"", e);
166: } catch (Parser.ParseException e) {
167: throw new ClassNotFoundException(
168: "Parsing compilation unit \"" + sourceResource
169: + "\"", e);
170: } catch (IOException e) {
171: throw new ClassNotFoundException(
172: "Parsing compilation unit \"" + sourceResource
173: + "\"", e);
174: }
175: }
176: }
|