Methods Summary |
---|
public synchronized void | addTransformer(javax.persistence.spi.ClassTransformer transformer)
transformers.add(transformer);
|
public void | addURL(java.net.URL url)Appends the specified URL to the list of URLs to search for
classes and resources.
appendURL(url);
|
public synchronized void | appendURL(java.io.File file)Adds a URL to the search list, based on the specified File.
This variant of the method makes sure that the URL is valid, in particular
encoding special characters (such as blanks) in the file path.
try {
appendURL(file.toURI().toURL());
} catch (MalformedURLException mue) {
_logger.log(Level.SEVERE,
"loader.ejbclassloader_bad_url_entry", file.toURI());
_logger.log(Level.SEVERE,
"loader.ejbclassloader_malformed_url", mue);
IOException ioe = new IOException();
ioe.initCause(mue);
throw ioe;
}
|
public synchronized void | appendURL(java.net.URL url)Add a url to the list of urls we search for a class's bytecodes.
try {
if (url == null) {
_logger.log(Level.INFO,
"loader.ejbclassloader_bad_url_entry", url);
return;
}
URLEntry entry = new URLEntry(url);
if ( !urlSet.contains(entry) ) {
entry.init();
// adds the url entry to the list
this.urlSet.add(entry);
if (entry.isJar) {
// checks the manifest if a jar
checkManifest(entry.zip, entry.file);
}
} else {
_logger.log(Level.FINE,
"[EJB-CL] Ignoring duplicate URL: " + url);
/*
*Clean up the unused entry or it could hold open a jar file.
*/
if (entry.zip != null) {
try {
entry.zip.reallyClose();
} catch (IOException ioe) {
_logger.log(Level.INFO, formatMsg("loader.ejbclassloader_exc_closing_dup_URLEntry", url),
ioe);
}
}
}
// clears the "not found" cache since we are adding a new url
clearNotFoundCaches();
} catch (IOException ioe) {
_logger.log(Level.SEVERE,
"loader.ejbclassloader_bad_url_entry", url);
_logger.log(Level.SEVERE,
"loader.ejbclassloader_malformed_url", ioe);
}
|
private void | checkManifest(java.util.jar.JarFile jar, java.io.File file)Checks the manifest of the given jar file.
if ( (jar == null) || (file == null) ) return;
Manifest man = jar.getManifest();
if (man == null) return;
synchronized (this) {
String cp = man.getMainAttributes().getValue(
Attributes.Name.CLASS_PATH);
if (cp == null) return;
StringTokenizer st = new StringTokenizer(cp, " ");
while (st.hasMoreTokens()) {
String entry = st.nextToken();
File newFile = new File(file.getParentFile(), entry);
// add to class path of this class loader
try {
appendURL(newFile);
} catch (MalformedURLException ex) {
_logger.log(Level.SEVERE,
"loader.ejbclassloader_malformed_url",ex);
}
}
}
|
private void | clearNotFoundCaches()Erases the memory of classes and resources that have been searched for
but not found.
this.notFoundResources.clear();
this.notFoundClasses.clear();
|
private void | closeOpenStreams()Closes any streams that remain open, logging a warning for each.
This method should be invoked when the loader will no longer be used
and the app will no longer explicitly close any streams it may have opened.
if (streams != null) {
SentinelInputStream[] toClose = streams.toArray(new SentinelInputStream[streams.size()]);
for (SentinelInputStream s : toClose) {
try {
s.closeWithWarning();
} catch (IOException ioe) {
_logger.log(Level.WARNING, "loader.ejbclassloader_error_closing_stream", ioe);
}
}
streams.clear();
streams = null;
}
|
public java.lang.ClassLoader | copy()Create a new instance of a sibling classloader
return new DelegatingClassLoader(this);
|
public void | done()This method should be called to free up the resources.
It helps garbage collection.
if( doneCalled ) {
return;
}
// Capture the fact that the classloader is now effectively disabled.
// First create a snapshot of our state. This should be called
// before setting doneCalled = true.
doneSnapshot = "EJBClassLoader.done() called ON " + this.toString()
+ "\n AT " + new Date() +
" \n BY :" + printStackTraceToString();
doneCalled = true;
// closes the jar handles and sets the url entries to null
int i = 0;
while (i < this.urlSet.size()) {
URLEntry u = (URLEntry) this.urlSet.get(i);
if (u.zip != null) {
try {
u.zip.reallyClose();
} catch (IOException ioe) {
_logger.log(Level.INFO, formatMsg("loader.ejbclassloader_exc_closing_URLEntry", u.source),
ioe);
}
}
if (u.table != null) {
u.table.clear();
u.table = null;
}
u = null;
i++;
}
closeOpenStreams();
// clears out the tables
if (this.urlSet != null) { this.urlSet.clear(); }
if (this.notFoundResources != null) { this.notFoundResources.clear(); }
if (this.notFoundClasses != null) { this.notFoundClasses.clear(); }
// sets all the objects to null
//this.urlSet = null;
//this.notFoundResources = null;
//this.notFoundClasses = null;
|
protected java.lang.Class | findClass(java.lang.String name)
ClassData classData = findClassData(name);
// Instruments the classes if the profiler's enabled
if (PreprocessorUtil.isPreprocessorEnabled()) {
// search thru the JARs for a file of the form java/lang/Object.class
String entryName = name.replace('.", '/") + ".class";
classData.classBytes = PreprocessorUtil.processClass(entryName, classData.classBytes);
}
// Define package information if necessary
int lastPackageSep = name.lastIndexOf('.");
if ( lastPackageSep != -1 ) {
String packageName = name.substring(0, lastPackageSep);
if( getPackage(packageName) == null ) {
try {
// There's a small chance that one of our parents
// could define the same package after getPackage
// returns null but before we call definePackage,
// since the parent classloader instances
// are not locked. So, just catch the exception
// that is thrown in that case and ignore it.
//
// It's unclear where we would get the info to
// set all spec and impl data for the package,
// so just use null. This is consistent will the
// JDK code that does the same.
definePackage(packageName, null, null, null,
null, null, null, null);
} catch(IllegalArgumentException iae) {
// duplicate attempt to define same package.
// safe to ignore.
_logger.log(Level.FINE, "duplicate package " +
"definition attempt for " + packageName, iae);
}
}
}
// Loop though the transformers here!!
try {
ArrayList<ClassTransformer> xformers = (ArrayList<ClassTransformer>) transformers.clone();
for (ClassTransformer transformer : xformers) {
// see javadocs of transform().
// It expects class name as java/lang/Object
// as opposed to java.lang.Object
String internalClassName = name.replace('.",'/");
byte[] transformedBytes = transformer.transform(this, internalClassName, null,
classData.pd, classData.classBytes);
if(transformedBytes!=null){ // null indicates no transformation
_logger.logp(Level.INFO, "EJBClassLoader",
"findClass", "{0} actually got transformed",
name);
classData.classBytes = transformedBytes;
}
}
} catch (IllegalClassFormatException icfEx) {
throw new ClassNotFoundException(icfEx.toString(), icfEx);
}
Class clazz = null;
try {
clazz = defineClass(name, classData.classBytes, 0, classData.classBytes.length, classData.pd);
return clazz;
} catch (UnsupportedClassVersionError ucve) {
throw new UnsupportedClassVersionError(
sm.getString("ejbClassLoader.unsupportedVersion", name,
System.getProperty("java.version")));
}
|
protected com.sun.enterprise.loader.EJBClassLoader$ClassData | findClassData(java.lang.String name)This method is responsible for locating the url from the class bytes
have to be read and reading the bytes. It does not actually define
the Class object.
if( doneCalled ) {
_logger.log(Level.WARNING,
formatMsg("loader.ejbclassloader_find_class_after_done", name, this.toString()), new Throwable());
throw new ClassNotFoundException(name);
}
String nf = (String) notFoundClasses.get(name);
if (nf != null && nf.equals(name) ) {
throw new ClassNotFoundException(name);
}
// search thru the JARs for a file of the form java/lang/Object.class
String entryName = name.replace('.", '/") + ".class";
int i = 0;
while (i < urlSet.size()) {
URLEntry u = (URLEntry) this.urlSet.get(i);
if (!u.hasItem(entryName)) {
i++;
continue;
}
byte[] result = loadClassData0(u, entryName);
if (result != null) return new ClassData(result, u.pd);
i++;
}
// add to the not found classes list
notFoundClasses.put(name, name);
throw new ClassNotFoundException(name);
|
public java.net.URL | findResource(java.lang.String name)
if( doneCalled ) {
_logger.log(Level.WARNING,
formatMsg("loader.ejbclassloader_find_resource_after_done", name, this.toString()),
new Throwable());
return null;
}
// resource is in the not found list
String nf = (String) notFoundResources.get(name);
if (nf != null && nf.equals(name) ) {
return null;
}
int i = 0;
while (i < this.urlSet.size()) {
URLEntry u = (URLEntry) this.urlSet.get(i);
if (!u.hasItem(name)) {
i++;
continue;
}
URL url = findResource0(u, name);
if (url != null) return url;
i++;
}
// add resource to the not found list
notFoundResources.put(name, name);
return null;
|
private java.net.URL | findResource0(com.sun.enterprise.loader.EJBClassLoader$URLEntry res, java.lang.String name)Internal implementation of find resource.
Object result =
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
if (res.isJar) {
try {
JarEntry jarEntry = res.zip.getJarEntry(name);
if (jarEntry != null) {
/*
*Use a custom URL with a special stream handler to
*prevent the JDK's JarURLConnection caching from
*locking the jar file until JVM exit.
*/
InternalURLStreamHandler handler = new InternalURLStreamHandler(res, name);
URI uri = new URI("jar", res.source + "!/" + name, null /* fragment */);
URL ret = new URL(uri.toURL(), "" /* spec */, handler);
handler.tieUrl(ret);
return ret;
}
} catch (Throwable thr) {
_logger.log(Level.INFO,
"loader.excep_in_ejbclassloader",thr);
}
} else { // directory
try {
File resourceFile =
new File(res.file.getCanonicalPath()
+ File.separator + name);
if (resourceFile.exists()) {
// If we make it this far,
// the resource is in the directory.
return resourceFile.toURL();
}
} catch (IOException e) {
_logger.log(Level.INFO,
"loader.excep_in_ejbclassloader",e);
}
}
return null;
} // End for -- each URL in classpath.
});
return (URL) result;
|
public java.util.Enumeration | findResources(java.lang.String name)Returns an enumeration of java.net.URL objects
representing all the resources with the given name.
if( doneCalled ) {
_logger.log(Level.WARNING,
"loader.ejbclassloader_done_already_called",
new Object[] { name, doneSnapshot });
return null;
}
// resource is in the not found list
String nf = (String) notFoundResources.get(name);
if (nf != null && nf.equals(name) ) {
return null;
}
List<URL> resourcesList = new ArrayList<URL>();
for (Iterator iter = this.urlSet.iterator(); iter.hasNext();) {
URLEntry urlEntry = (URLEntry) iter.next();
URL url = findResource0(urlEntry, name);
if (url != null) {
resourcesList.add(url);
}
}
if (resourcesList.size() == 0) {
// add resource to the not found list
notFoundResources.put(name, name);
}
return (new Vector(resourcesList)).elements();
|
private static java.lang.String | formatMsg(java.lang.String key, java.lang.Object args)Looks up the key in the logger's resource bundle and substitutes any
arguments provided into the looked-up string.
String fmt = _logger.getResourceBundle().getString(key);
return MessageFormat.format(fmt, args);
|
private byte[] | getClassData(java.io.InputStream istream)Returns the byte array from the given input stream.
BufferedInputStream bstream = new BufferedInputStream(istream);;
byte[] buf = new byte[4096];
ByteArrayOutputStream bout = new ByteArrayOutputStream();
int num = 0;
try {
while( (num = bstream.read(buf)) != -1) {
bout.write(buf, 0, num);
}
} finally {
if (bstream != null) {
try {
bstream.close();
} catch (IOException closeIOE) {
EJBClassLoader._logger.log(Level.INFO, "loader.excep_in_ejbclassloader", closeIOE);
}
}
}
return bout.toByteArray();
|
public java.lang.String | getClasspath()Returns all the "file" protocol resources of this EJBClassLoader,
concatenated to a classpath string.
Notice that this method is called by the setClassPath() method of
org.apache.catalina.loader.WebappLoader, since this EJBClassLoader does
not extend off of URLClassLoader.
StringBuffer strBuf = null;
URL[] urls = getURLs();
if (urls != null) {
for (int i=0; i<urls.length; i++) {
if (urls[i].getProtocol().equals("file")) {
if (strBuf == null) {
strBuf = new StringBuffer();
}
if (i > 0) {
strBuf.append(File.pathSeparator);
}
strBuf.append(urls[i].getFile());
}
}
}
return (strBuf != null) ? strBuf.toString() : null;
|
public java.io.InputStream | getResourceAsStream(java.lang.String name)
InputStream stream = super.getResourceAsStream(name);
/*
*Make sure not to wrap the stream if it already is a wrapper.
*/
if (stream != null) {
if (! (stream instanceof SentinelInputStream)) {
stream = new SentinelInputStream(stream);
}
}
return stream;
|
private synchronized java.util.Vector | getStreams()Returns the vector of open streams; creates it if needed.
if (streams == null) {
streams = new Vector<SentinelInputStream>();
}
return streams;
|
public synchronized java.net.URL[] | getURLs()Returns the urls of this class loader.
URL[] url = null;
if (this.urlSet != null) {
url = new URL[this.urlSet.size()];
for (int i=0; i<url.length; i++) {
url[i] = ((URLEntry)this.urlSet.get(i)).source;
}
} else {
url = new URL[0];
}
return url;
|
public boolean | isDone()
return doneCalled;
|
private byte[] | loadClassData0(com.sun.enterprise.loader.EJBClassLoader$URLEntry res, java.lang.String entryName)Internal implementation of load class.
Object result =
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
InputStream classStream = null;
try {
if (res.isJar) { // It is a jarfile..
JarFile zip = res.zip;
JarEntry entry = zip.getJarEntry(entryName);
if (entry != null) {
classStream = zip.getInputStream(entry);
byte[] classData = getClassData(classStream);
res.setProtectionDomain(EJBClassLoader.this, entry.getCertificates());
return classData;
}
} else { // Its a directory....
File classFile = new File (res.file,
entryName.replace('/", File.separatorChar));
if (classFile.exists()) {
try {
classStream = new FileInputStream(classFile);
byte[] classData = getClassData(classStream);
res.setProtectionDomain(EJBClassLoader.this, null);
return classData;
} finally {
/*
*Close the stream only if this is a directory. The stream for
*a jar/zip file was opened elsewhere and should remain open after this
*method completes.
*/
if (classStream != null) {
try {
classStream.close();
} catch (IOException closeIOE) {
_logger.log(Level.INFO, "loader.excep_in_ejbclassloader", closeIOE);
}
}
}
}
}
} catch (IOException ioe) {
_logger.log(Level.INFO,
"loader.excep_in_ejbclassloader", ioe);
}
return null;
}
});
return (byte[]) result;
|
private java.lang.String | printStackTraceToString()Formats the caller's stack trace to a string.
StringBuilder sb = new StringBuilder();
StackTraceElement[] elements = Thread.currentThread().getStackTrace();
/*
*Start with element 1 and not 0 to avoid displaying the stack frame
*for the call to this method.
*/
for (int i = 1; i < elements.length; i++) {
sb.append(elements[i].toString()).append(LINE_SEP);
}
return sb.toString();
|
public synchronized void | refresh()Refreshes the memory of the class loader. This involves clearing the
not-found cahces and recreating the hash tables for the URLEntries that
record the files accessible for each.
Code that creates an EJBClassLoader and then adds files to a directory
that is in the loader's classpath should invoke this method after the new
file(s) have been added in order to update the class loader's data
structures which optimize class and resource searches.
clearNotFoundCaches();
// for (URLEntry entry : urlSet) {
// entry.cacheItems();
// }
|
public java.lang.String | toString()Returns a string representation of this class loader.
StringBuffer buffer = new StringBuffer();
buffer.append("EJBClassLoader : \n");
if( doneCalled ) {
buffer.append("doneCalled = true" + "\n");
if( doneSnapshot != null ) {
buffer.append("doneSnapshot = " + doneSnapshot);
}
} else {
buffer.append("urlSet = " + this.urlSet + "\n");
buffer.append("doneCalled = false " + "\n");
}
buffer.append(" Parent -> " + getParent() + "\n");
return buffer.toString();
|