/*
* Janino - An embedded Java[TM] compiler
* Copyright (C) 2001-2004 Arno Unkrig
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information:
* Arno Unkrig
* Ferdinand-Miller-Platz 10
* 80335 Muenchen
* Germany
* http://www.janino.net
* maintainer@janino.net
*/
package net.janino;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Iterator;
import java.util.Set;
import net.janino.util.ClassFile;
import net.janino.util.TunnelException;
import net.janino.util.resource.ResourceFinder;
/**
* This {@link net.janino.IClassLoader} finds, scans and parses compilation units.
* <p>
* Notice that it does not compile them!
*/
final class JavaSourceIClassLoader extends IClassLoader {
private static final boolean DEBUG = false;
private final ResourceFinder sourceFinder;
private final String optionalCharacterEncoding;
private final Set uncompiledCompilationUnits; // Java.CompilationUnit
/**
* Notice that the <code>uncompiledCompilationUnits</code> set is both read and written
* by the {@link JavaSourceIClassLoader}: As it searches for {@link IClass}es, it looks
* into <code>uncompiledCompilationUnits</code> for class declarations, and as it opens,
* scans and parses compilation units on-the-fly, it adds them to
* <code>uncompiledCompilationUnits</code>.
*/
public JavaSourceIClassLoader(
ResourceFinder sourceFinder,
String optionalCharacterEncoding,
Set uncompiledCompilationUnits,
IClassLoader optionalParentIClassLoader
) {
super(optionalParentIClassLoader);
this.sourceFinder = sourceFinder;
this.optionalCharacterEncoding = optionalCharacterEncoding;
this.uncompiledCompilationUnits = uncompiledCompilationUnits;
super.postConstruct();
}
/**
* @param type field descriptor of the {@IClass} to load, e.g. "Lpkg1/pkg2/Outer$Inner;"
* @throws TunnelException wraps a {@link Scanner.ScanException}
* @throws TunnelException wraps a {@link Parser.ParseException}
* @throws TunnelException wraps a {@link IOException}
*/
public IClass findIClass(final String type) {
if (JavaSourceIClassLoader.DEBUG) System.out.println("type = " + type);
// Class type.
String className = Descriptor.toClassName(type); // E.g. "pkg1.pkg2.Outer$Inner"
if (JavaSourceIClassLoader.DEBUG) System.out.println("2 className = \"" + className + "\"");
// Do not attempt to load classes from package "java".
if (className.startsWith("java.")) return null;
// Check the already-parsed compilation units.
for (Iterator it = this.uncompiledCompilationUnits.iterator(); it.hasNext();) {
Java.CompilationUnit cu = (Java.CompilationUnit) it.next();
IClass res = cu.findClass(className);
if (res != null) {
this.defineIClass(res);
return res;
}
}
try {
// Find source file.
URL sourceURL = this.sourceFinder.findResource(ClassFile.getSourceResourceName(className));
if (sourceURL == null) return null;
if (JavaSourceIClassLoader.DEBUG) System.out.println("sourceURL=" + sourceURL);
// Scan and parse the source file.
Java.CompilationUnit cu;
InputStream inputStream = sourceURL.openStream();
try {
Scanner scanner = new Scanner(sourceURL.getFile(), inputStream, this.optionalCharacterEncoding);
Parser parser = new Parser(scanner);
cu = parser.parseCompilationUnit();
} finally {
try { inputStream.close(); } catch (IOException ex) {}
}
// Remember compilation unit for later compilation.
this.uncompiledCompilationUnits.add(cu);
// Find the class/interface declaration in the com
IClass res = cu.findClass(className);
if (res == null) throw new Parser.ParseException("Source file \"" + sourceURL.getFile() + "\" does not declare class \"" + className + "\"", (Scanner.Location) null);
this.defineIClass(res);
return res;
} catch (Scanner.ScanException e) {
throw new TunnelException(e);
} catch (Parser.ParseException e) {
throw new TunnelException(e);
} catch (IOException e) {
throw new TunnelException(e);
}
}
}