EnhancerClassLoaderpublic class EnhancerClassLoader extends URLClassLoader Implements a ClassLoader which automatically enchances the .class files
according to the JDOMetaData information in the jar archive. |
Fields Summary |
---|
public static final String | DO_SIMPLE_TIMING | public static final String | VERBOSE_LEVEL | public static final String | VERBOSE_LEVEL_QUIET | public static final String | VERBOSE_LEVEL_WARN | public static final String | VERBOSE_LEVEL_VERBOSE | public static final String | VERBOSE_LEVEL_DEBUG | private boolean | debug | private boolean | doTiming | private PrintWriter | out | private ByteCodeEnhancer | enhancer | private com.sun.jdo.api.persistence.enhancer.meta.JDOMetaData | metaData | private Properties | settings | private WeakReference | outByteCodeRef | private final sun.misc.URLClassPath | ucp | private final AccessControlContext | acc |
Constructors Summary |
---|
public EnhancerClassLoader(URL[] urls, com.sun.jdo.api.persistence.enhancer.meta.JDOMetaData metaData, Properties settings, PrintWriter out)Creates a new EnhancerClassLoader for the specified url.
this(urls);
init(metaData, settings, out);
| protected EnhancerClassLoader(URL[] urls)Creates a new EnhancerClassLoader for the specified url.
super(urls);
acc = AccessController.getContext();
ucp = new URLClassPath(urls);
checkUCP(urls);
| protected EnhancerClassLoader(URL[] urls, ClassLoader loader)Creates a new EnhancerClassLoader for the specified url.
super(urls, loader);
acc = AccessController.getContext();
ucp = new URLClassPath(urls);
checkUCP(urls);
| public EnhancerClassLoader(String classpath, Properties settings, PrintWriter out)Creates a new EnhancerClassLoader for the specified url.
this(pathToURLs(classpath));
JDOMetaData metaData = new JDOMetaDataModelImpl(Model.ENHANCER, out);
init(metaData, settings, out);
| public EnhancerClassLoader(URL[] urls, Properties settings, PrintWriter out)Creates a new EnhancerClassLoader for the specified url.
this(urls);
JDOMetaData metaData = new JDOMetaDataModelImpl(Model.ENHANCER, out);
init(metaData, settings, out);
| public EnhancerClassLoader(String classpath, com.sun.jdo.api.persistence.enhancer.meta.JDOMetaData metaData, Properties settings, PrintWriter out)Creates a new EnhancerClassLoader for the specified url.
this(pathToURLs(classpath));
init(metaData, settings, out);
|
Methods Summary |
---|
protected void | addURL(java.net.URL url)Appends the specified URL to the list of URLs to search for
classes and resources.
throw new UnsupportedOperationException("Not implemented yet: EnhancerClassLoader.addURL(URL)");//NOI18N
//super.addURL(url);
//ucp.addURL(url);
| private void | checkUCP(java.net.URL[] urls)
// ensure classpath is not empty
if (null == urls) {
throw new IllegalArgumentException("urls == null");//NOI18N
}
if (urls.length == 0) {
throw new IllegalArgumentException("urls.length == 0");//NOI18N
}
for (int i = 0; i < urls.length; i++) {
super.addURL(urls[i]);
}
| private java.lang.Class | defineClass(java.lang.String name, sun.misc.Resource res)Defines a Class using the class bytes obtained from the specified
Resource. The resulting Class must be resolved before it can be
used.
int i = name.lastIndexOf('.");
URL url = res.getCodeSourceURL();
if (i != -1) {
String pkgname = name.substring(0, i);
// Check if package already loaded.
Package pkg = getPackage(pkgname);
Manifest man = res.getManifest();
if (pkg != null) {
// Package found, so check package sealing.
boolean ok;
if (pkg.isSealed()) {
// Verify that code source URL is the same.
ok = pkg.isSealed(url);
} else {
// Make sure we are not attempting to seal the package
// at this code source URL.
ok = (man == null) || !isSealed(pkgname, man);
}
if (!ok) {
throw new SecurityException("sealing violation");//NOI18N
}
} else {
if (man != null) {
definePackage(pkgname, man, url);
} else {
definePackage(pkgname, null, null, null, null, null, null, null);
}
}
}
// Now read the class bytes and define the class
byte[] b = res.getBytes();
Certificate[] certs = res.getCertificates();
CodeSource cs = new CodeSource(url, certs);
//@olsen: performance bug 4457471: circumvent enhancer for
// non-enhancable classes
final String classPath = name.replace('.", '/");
if (!metaData.isTransientClass(classPath)) {
// Add enhancement here
b = enhance(name, b, 0, b.length);
}
return defineClass(name, b, 0, b.length, cs);
| private byte[] | enhance(java.lang.String name, byte[] data, int off, int len)
//message("EnhancerClassLoader: enhance class: " + name);
final byte[] result;
try {
// create enhancer if not done yet
if (null == enhancer) {
enhancer = new FilterEnhancer(metaData, settings, out, null);
if (doTiming) {
// wrap with timing filter enhancer object
enhancer = new ByteCodeEnhancerTimer(enhancer);
}
}
// create input and output byte streams
ByteArrayInputStream inByteCode
= new ByteArrayInputStream(data, off, len);
ByteArrayOutputStream outByteCode
= ((null == outByteCodeRef)
? null : (ByteArrayOutputStream)outByteCodeRef.get());
if (null == outByteCode) {
outByteCode = new ByteArrayOutputStream(10000);
outByteCodeRef = new WeakReference(outByteCode);
}
outByteCode.reset();
// enhance class
boolean changed
= enhancer.enhanceClassFile(inByteCode, outByteCode);
// check whether class has been enhanced
result = (changed ? outByteCode.toByteArray() : data);
} catch (EnhancerUserException e) {
//@olsen: 4370739
message(e);
final String msg = ("Exception caught while loading class '"//NOI18N
+ name + "' : " + e);//NOI18N
throw new ClassNotFoundException(msg, e);
} catch(EnhancerFatalError e) {
//@olsen: 4370739
message(e);
final String msg = ("Exception caught while loading class '"//NOI18N
+ name + "' : " + e);//NOI18N
// discard enhancer since it might have become inconsistent
enhancer = null;
throw new ClassNotFoundException(msg, e);
}
return result;
| private java.lang.Class | findAndEnhanceClass(java.lang.String name)Finds and loads the class with the specified name from the URL search
path. Any URLs referring to JAR files are loaded and opened as needed
until the class is found.
try {
if (doTiming) {
Support.timer.push("EnhancerClassLoader.findAndEnhanceClass(String)",//NOI18N
"EnhancerClassLoader.findAndEnhanceClass(" + name + ")");//NOI18N
}
return (Class)
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws ClassNotFoundException {
String path = name.replace('.", '/").concat(".class");//NOI18N
//message("path=" + path);
Resource res = ucp.getResource(path, false);
if (res != null) {
try {
return defineClass(name, res);
} catch (IOException e) {
final String msg
= ("Exception caught while loading class '"//NOI18N
+ name + "' : " + e);//NOI18N
throw new ClassNotFoundException(msg, e);
}
} else {
// ok if class resource not found (e.g. java.*)
//throw new ClassNotFoundException(name);
return null;
}
}
}, acc);
} catch (PrivilegedActionException pae) {
throw (ClassNotFoundException) pae.getException();
} finally {
if (doTiming) {
Support.timer.pop();
}
}
| private void | init(com.sun.jdo.api.persistence.enhancer.meta.JDOMetaData metaData, java.util.Properties settings, java.io.PrintWriter out)Initialize the EnhancingClassLoader
this.out = out;
final String verboseLevel
= (settings == null ? null
: settings.getProperty(FilterEnhancer.VERBOSE_LEVEL));
this.debug = FilterEnhancer.VERBOSE_LEVEL_DEBUG.equals(verboseLevel);
this.settings = settings;
this.metaData = metaData;
this.enhancer = null;
if (settings != null) {
final String timing
= settings.getProperty(FilterEnhancer.DO_SIMPLE_TIMING);
this.doTiming = Boolean.valueOf(timing).booleanValue();
}
if (this.doTiming) {
// wrap with timing meta data object
this.metaData = new JDOMetaDataTimer(metaData);
}
message("EnhancerClassLoader: UCP = {");//NOI18N
final URL[] urls = getURLs();
for (int i = 0; i < urls.length; i++) {
message(" " + urls[i]);//NOI18N
}
message("}");//NOI18N
message("EnhancerClassLoader: jdoMetaData = " + metaData);//NOI18N
| private boolean | isSealed(java.lang.String name, java.util.jar.Manifest man)Returns true if the specified package name is sealed according to the
given manifest.
String path = name.replace('.", '/").concat("/");//NOI18N
Attributes attr = man.getAttributes(path);
String sealed = null;
if (attr != null) {
sealed = attr.getValue(Name.SEALED);
}
if (sealed == null) {
if ((attr = man.getMainAttributes()) != null) {
sealed = attr.getValue(Name.SEALED);
}
}
return "true".equalsIgnoreCase(sealed);//NOI18N
| public synchronized java.lang.Class | loadClass(java.lang.String name, boolean resolve)
message();
message("EnhancerClassLoader: loading class: " + name);//NOI18N
try {
Class c = null;
final String classPath = name.replace('.", '/");
// At least these packages must be delegated to parent class
// loader:
// java/lang, (Object, ...)
// java/util, (Collection)
// java/io, (PrintWriter)
// javax/sql, (PMF->javax.sql.DataSource)
// javax/transaction (Tx->javax.transaction.Synchronization)
//
//@olsen: delegate loading of "safe" classes to parent
//if (metaData.isTransientClass(classPath)) {
//
//@olsen: only delegate loading of bootstrap classes to parent
//if (classPath.startsWith("java/lang/")) {
//
//@olsen: performance bug 4457471: delegate loading of F4J
// persistence classes to parent tp prevent passing these and
// other IDE classes plus database drivers etc. to the enhancer!
//if (classPath.startsWith("java/lang/")
// || classPath.startsWith("com/sun/jdo/")) {
//
//@olsen: bug 4480618: delegate loading of javax.{sql,transaction}
// classes to parent class loader to support user-defined
// DataSource and Synchronization objects to be passed to the
// TP runtime. By the same argument, java.{util,io} classes need
// also be loaded by the parent class loader. This has been
// the case since the EnhancerClassLoader will never find these
// bootstrap classes in the passed Classpath. However, for
// efficiency and clarity, this delegation should be expressed
// by testing for entire "java/" package in the check here.
if (classPath.startsWith("java/")//NOI18N
|| classPath.startsWith("javax/sql/")//NOI18N
|| classPath.startsWith("javax/transaction/")//NOI18N
|| classPath.startsWith("com/sun/jdo/")) {//NOI18N
message("EnhancerClassLoader: bootstrap class, using parent loader for class: " + name);//NOI18N
return super.loadClass(name, resolve);
//@olsen: dropped alternative approach
/*
message("EnhancerClassLoader: transient class, skipping enhancing: " + name);//NOI18N
// get a byte array output stream to collect byte code
ByteArrayOutputStream outByteCode
= ((null == outByteCodeRef)
? null : (ByteArrayOutputStream)outByteCodeRef.get());
if (null == outByteCode) {
outByteCode = new ByteArrayOutputStream(10000);
outByteCodeRef = new WeakReference(outByteCode);
}
outByteCode.reset();
// find byte code of class
final InputStream is = getSystemResourceAsStream(name);
//@olsen: (is == null) ?!
// copy byte code of class into byte array
final byte[] data;
try {
int b;
while ((b = is.read()) >= 0) {
outByteCode.write(b);
}
data = outByteCode.toByteArray();
} catch (IOException e) {
final String msg
= ("Exception caught while loading class '"//NOI18N
+ name + "' : " + e);//NOI18N
throw new ClassNotFoundException(msg, e);
}
// convert the byte code into class object
c = defineClass(name, data, 0, data.length);
*/
}
//@olsen: check if class has been loaded already
if (c == null) {
c = findLoadedClass(name);
if (c != null) {
message("EnhancerClassLoader: class already loaded: " + name);//NOI18N
}
}
if (c == null) {
c = findAndEnhanceClass(name);
}
// as a last resort, if the class couldn't be found, try
// loading class by parent class loader
if (c == null) {
message("EnhancerClassLoader: class not found, using parent loader for class: " + name);//NOI18N
return super.loadClass(name, resolve);
}
message();
message("EnhancerClassLoader: loaded class: " + name);//NOI18N
if (resolve) {
resolveClass(c);
}
message();
message("EnhancerClassLoader: loaded+resolved class: " + name);//NOI18N
return c;
} catch (RuntimeException e) {
// log exception only
message();
message("EnhancerClassLoader: EXCEPTION SEEN: " + e);//NOI18N
//e.printStackTrace(out);
throw e;
} catch (ClassNotFoundException e) {
// log exception only
message();
message("EnhancerClassLoader: EXCEPTION SEEN: " + e);//NOI18N
//e.printStackTrace(out);
throw e;
}
| private final void | message()
//@olsen: 4370739
if (debug) {
out.println();
}
| private final void | message(java.lang.String s)
if (debug) {
out.println(s);
}
| private final void | message(java.lang.Exception e)
if (debug) {
final String msg = ("Exception caught: " + e);//NOI18N
out.println(msg);
e.printStackTrace(out);
}
| public static java.net.URL[] | pathToURLs(java.lang.String classpath)
return URLClassPath.pathToURLs(classpath);
|
|