groovyclassloader.java
来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 854 行 · 第 1/3 页
JAVA
854 行
/*
* $Id: GroovyClassLoader.java 4445 2006-12-17 22:35:15Z blackdrag $
*
* Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
*
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided that the
* following conditions are met:
* 1. Redistributions of source code must retain copyright statements and
* notices. Redistributions must also contain a copy of this document.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name "groovy" must not be used to endorse or promote products
* derived from this Software without prior written permission of The Codehaus.
* For written permission, please contact info@codehaus.org.
* 4. Products derived from this Software may not be called "groovy" nor may
* "groovy" appear in their names without prior written permission of The
* Codehaus. "groovy" is a registered trademark of The Codehaus.
* 5. Due credit should be given to The Codehaus - http://groovy.codehaus.org/
*
* THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
*/
/**
* @TODO: multi threaded compiling of the same class but with different roots
* for compilation... T1 compiles A, which uses B, T2 compiles B... mark A and B
* as parsed and then synchronize compilation. Problems: How to synchronize?
* How to get error messages?
*
*/
package groovy.lang;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.codehaus.groovy.ast.ClassNode;
import org.codehaus.groovy.ast.ModuleNode;
import org.codehaus.groovy.classgen.Verifier;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.Phases;
import org.codehaus.groovy.control.SourceUnit;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
/**
* A ClassLoader which can load Groovy classes. The loaded classes are cached,
* classes from other classlaoders should not be cached. To be able to load a
* script that was asked for earlier but was created later it is essential not
* to keep anything like a "class not found" information for that class name.
* This includes possible parent loaders. Classes that are not chached are always
* reloaded.
*
* @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
* @author Guillaume Laforge
* @author Steve Goetze
* @author Bing Ran
* @author <a href="mailto:scottstirling@rcn.com">Scott Stirling</a>
* @author <a href="mailto:blackdrag@gmx.org">Jochen Theodorou</a>
* @version $Revision: 4445 $
*/
public class GroovyClassLoader extends URLClassLoader {
/**
* this cache contains the loaded classes or PARSING, if the class is currently parsed
*/
protected Map classCache = new HashMap();
protected Map sourceCache = new HashMap();
private CompilerConfiguration config;
private Boolean recompile = null;
// use 1000000 as offset to avoid conflicts with names form the GroovyShell
private static int scriptNameCounter = 1000000;
private GroovyResourceLoader resourceLoader = new GroovyResourceLoader() {
public URL loadGroovySource(final String filename) throws MalformedURLException {
URL file = (URL) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return getSourceFile(filename);
}
});
return file;
}
};
/**
* creates a GroovyClassLoader using the current Thread's context
* Class loader as parent.
*/
public GroovyClassLoader() {
this(Thread.currentThread().getContextClassLoader());
}
/**
* creates a GroovyClassLoader using the given ClassLoader as parent
*/
public GroovyClassLoader(ClassLoader loader) {
this(loader, null);
}
/**
* creates a GroovyClassLoader using the given GroovyClassLoader as parent.
* This loader will get the parent's CompilerConfiguration
*/
public GroovyClassLoader(GroovyClassLoader parent) {
this(parent, parent.config, false);
}
/**
* creates a GroovyClassLaoder.
* @param parent the parten class loader
* @param config the compiler configuration
* @param useConfigurationClasspath determines if the configurations classpath should be added
*/
public GroovyClassLoader(ClassLoader parent, CompilerConfiguration config, boolean useConfigurationClasspath) {
super(new URL[0],parent);
if (config==null) config = CompilerConfiguration.DEFAULT;
this.config = config;
if (useConfigurationClasspath) {
for (Iterator it=config.getClasspath().iterator(); it.hasNext();) {
String path = (String) it.next();
this.addClasspath(path);
}
}
}
/**
* creates a GroovyClassLoader using the given ClassLoader as parent.
*/
public GroovyClassLoader(ClassLoader loader, CompilerConfiguration config) {
this(loader,config,true);
}
public void setResourceLoader(GroovyResourceLoader resourceLoader) {
if (resourceLoader == null) {
throw new IllegalArgumentException("Resource loader must not be null!");
}
this.resourceLoader = resourceLoader;
}
public GroovyResourceLoader getResourceLoader() {
return resourceLoader;
}
/**
* Loads the given class node returning the implementation Class
*
* @param classNode
* @return a class
*/
public Class defineClass(ClassNode classNode, String file) {
//return defineClass(classNode, file, "/groovy/defineClass");
throw new DeprecationException("the method GroovyClassLoader#defineClass(ClassNode, String) is no longer used and removed");
}
/**
* Loads the given class node returning the implementation Class.
*
* WARNING: this compilation is not synchronized
*
* @param classNode
* @return a class
*/
public Class defineClass(ClassNode classNode, String file, String newCodeBase) {
CodeSource codeSource = null;
try {
codeSource = new CodeSource(new URL("file", "", newCodeBase), (java.security.cert.Certificate[]) null);
} catch (MalformedURLException e) {
//swallow
}
CompilationUnit unit = createCompilationUnit(config,codeSource);
ClassCollector collector = createCollector(unit,classNode.getModule().getContext());
try {
unit.addClassNode(classNode);
unit.setClassgenCallback(collector);
unit.compile(Phases.CLASS_GENERATION);
return collector.generatedClass;
} catch (CompilationFailedException e) {
throw new RuntimeException(e);
}
}
/**
* Parses the given file into a Java class capable of being run
*
* @param file the file name to parse
* @return the main class defined in the given script
*/
public Class parseClass(File file) throws CompilationFailedException, IOException {
return parseClass(new GroovyCodeSource(file));
}
/**
* Parses the given text into a Java class capable of being run
*
* @param text the text of the script/class to parse
* @param fileName the file name to use as the name of the class
* @return the main class defined in the given script
*/
public Class parseClass(String text, String fileName) throws CompilationFailedException {
return parseClass(new ByteArrayInputStream(text.getBytes()), fileName);
}
/**
* Parses the given text into a Java class capable of being run
*
* @param text the text of the script/class to parse
* @return the main class defined in the given script
*/
public Class parseClass(String text) throws CompilationFailedException {
return parseClass(new ByteArrayInputStream(text.getBytes()), "script" + System.currentTimeMillis() + ".groovy");
}
/**
* Parses the given character stream into a Java class capable of being run
*
* @param in an InputStream
* @return the main class defined in the given script
*/
public Class parseClass(InputStream in) throws CompilationFailedException {
return parseClass(in, generateScriptName());
}
public synchronized String generateScriptName() {
scriptNameCounter++;
return "script"+scriptNameCounter+".groovy";
}
public Class parseClass(final InputStream in, final String fileName) throws CompilationFailedException {
// For generic input streams, provide a catch-all codebase of
// GroovyScript
// Security for these classes can be administered via policy grants with
// a codebase of file:groovy.script
GroovyCodeSource gcs = (GroovyCodeSource) AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new GroovyCodeSource(in, fileName, "/groovy/script");
}
});
return parseClass(gcs);
}
public Class parseClass(GroovyCodeSource codeSource) throws CompilationFailedException {
return parseClass(codeSource, codeSource.isCachable());
}
/**
* Parses the given code source into a Java class. If there is a class file
* for the given code source, then no parsing is done, instead the cached class is returned.
*
* @param shouldCacheSource if true then the generated class will be stored in the source cache
*
* @return the main class defined in the given script
*/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?