| Method from org.apache.catalina.loader.WebappClassLoader Detail: |
synchronized void addJar(String jar,
JarFile jarFile,
File file) throws IOException {
if (jar == null)
return;
if (jarFile == null)
return;
if (file == null)
return;
if (log.isDebugEnabled())
log.debug("addJar(" + jar + ")");
int i;
if ((jarPath != null) && (jar.startsWith(jarPath))) {
String jarName = jar.substring(jarPath.length());
while (jarName.startsWith("/"))
jarName = jarName.substring(1);
String[] result = new String[jarNames.length + 1];
for (i = 0; i < jarNames.length; i++) {
result[i] = jarNames[i];
}
result[jarNames.length] = jarName;
jarNames = result;
}
try {
// Register the JAR for tracking
long lastModified =
((ResourceAttributes) resources.getAttributes(jar))
.getLastModified();
String[] result = new String[paths.length + 1];
for (i = 0; i < paths.length; i++) {
result[i] = paths[i];
}
result[paths.length] = jar;
paths = result;
long[] result3 = new long[lastModifiedDates.length + 1];
for (i = 0; i < lastModifiedDates.length; i++) {
result3[i] = lastModifiedDates[i];
}
result3[lastModifiedDates.length] = lastModified;
lastModifiedDates = result3;
} catch (NamingException e) {
// Ignore
}
// If the JAR currently contains invalid classes, don't actually use it
// for classloading
if (!validateJarFile(file))
return;
JarFile[] result2 = new JarFile[jarFiles.length + 1];
for (i = 0; i < jarFiles.length; i++) {
result2[i] = jarFiles[i];
}
result2[jarFiles.length] = jarFile;
jarFiles = result2;
// Add the file to the list
File[] result4 = new File[jarRealFiles.length + 1];
for (i = 0; i < jarRealFiles.length; i++) {
result4[i] = jarRealFiles[i];
}
result4[jarRealFiles.length] = file;
jarRealFiles = result4;
}
|
public void addLifecycleListener(LifecycleListener listener) {
}
Add a lifecycle event listener to this component. |
public void addPermission(String path) {
if (path == null) {
return;
}
if (securityManager != null) {
Permission permission = null;
if( path.startsWith("jndi:") || path.startsWith("jar:jndi:") ) {
if (!path.endsWith("/")) {
path = path + "/";
}
permission = new JndiPermission(path + "*");
addPermission(permission);
} else {
if (!path.endsWith(File.separator)) {
permission = new FilePermission(path, "read");
addPermission(permission);
path = path + File.separator;
}
permission = new FilePermission(path + "-", "read");
addPermission(permission);
}
}
}
If there is a Java SecurityManager create a read FilePermission
or JndiPermission for the file directory path. |
public void addPermission(URL url) {
if (url != null) {
addPermission(url.toString());
}
}
If there is a Java SecurityManager create a read FilePermission
or JndiPermission for URL. |
public void addPermission(Permission permission) {
if ((securityManager != null) && (permission != null)) {
permissionList.add(permission);
}
}
If there is a Java SecurityManager create a Permission. |
public void addRepository(String repository) {
// Ignore any of the standard repositories, as they are set up using
// either addJar or addRepository
if (repository.startsWith("/WEB-INF/lib")
|| repository.startsWith("/WEB-INF/classes"))
return;
// Add this repository to our underlying class loader
try {
URL url = new URL(repository);
super.addURL(url);
hasExternalRepositories = true;
repositoryURLs = null;
} catch (MalformedURLException e) {
IllegalArgumentException iae = new IllegalArgumentException
("Invalid repository: " + repository);
iae.initCause(e);
throw iae;
}
}
Add a new repository to the set of places this ClassLoader can look for
classes to be loaded. |
synchronized void addRepository(String repository,
File file) {
// Note : There should be only one (of course), but I think we should
// keep this a bit generic
if (repository == null)
return;
if (log.isDebugEnabled())
log.debug("addRepository(" + repository + ")");
int i;
// Add this repository to our internal list
String[] result = new String[repositories.length + 1];
for (i = 0; i < repositories.length; i++) {
result[i] = repositories[i];
}
result[repositories.length] = repository;
repositories = result;
// Add the file to the list
File[] result2 = new File[files.length + 1];
for (i = 0; i < files.length; i++) {
result2[i] = files[i];
}
result2[files.length] = file;
files = result2;
}
Add a new repository to the set of places this ClassLoader can look for
classes to be loaded. |
protected void addURL(URL url) {
super.addURL(url);
hasExternalRepositories = true;
repositoryURLs = null;
}
Add the specified URL to the classloader. |
protected void clearReferences() {
// Unregister any JDBC drivers loaded by this classloader
Enumeration drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = (Driver) drivers.nextElement();
if (driver.getClass().getClassLoader() == this) {
try {
DriverManager.deregisterDriver(driver);
} catch (SQLException e) {
log.warn("SQL driver deregistration failed", e);
}
}
}
// Null out any static or final fields from loaded classes,
// as a workaround for apparent garbage collection bugs
if (ENABLE_CLEAR_REFERENCES) {
Iterator loadedClasses = ((HashMap) resourceEntries.clone()).values().iterator();
while (loadedClasses.hasNext()) {
ResourceEntry entry = (ResourceEntry) loadedClasses.next();
if (entry.loadedClass != null) {
Class clazz = entry.loadedClass;
try {
Field[] fields = clazz.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
int mods = field.getModifiers();
if (field.getType().isPrimitive()
|| (field.getName().indexOf("$") != -1)) {
continue;
}
if (Modifier.isStatic(mods)) {
try {
field.setAccessible(true);
if (Modifier.isFinal(mods)) {
if (!((field.getType().getName().startsWith("java."))
|| (field.getType().getName().startsWith("javax.")))) {
nullInstance(field.get(null));
}
} else {
field.set(null, null);
if (log.isDebugEnabled()) {
log.debug("Set field " + field.getName()
+ " to null in class " + clazz.getName());
}
}
} catch (Throwable t) {
if (log.isDebugEnabled()) {
log.debug("Could not set field " + field.getName()
+ " to null in class " + clazz.getName(), t);
}
}
}
}
} catch (Throwable t) {
if (log.isDebugEnabled()) {
log.debug("Could not clean fields for class " + clazz.getName(), t);
}
}
}
}
}
// Clear the IntrospectionUtils cache.
IntrospectionUtils.clear();
// Clear the classloader reference in common-logging
org.apache.juli.logging.LogFactory.release(this);
// Clear the classloader reference in the VM's bean introspector
java.beans.Introspector.flushCaches();
}
|
public void closeJARs(boolean force) {
if (jarFiles.length > 0) {
synchronized (jarFiles) {
if (force || (System.currentTimeMillis()
> (lastJarAccessed + 90000))) {
for (int i = 0; i < jarFiles.length; i++) {
try {
if (jarFiles[i] != null) {
jarFiles[i].close();
jarFiles[i] = null;
}
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.debug("Failed to close JAR", e);
}
}
}
}
}
}
}
Used to periodically signal to the classloader to release
JAR resources. |
protected static void deleteDir(File dir) {
String files[] = dir.list();
if (files == null) {
files = new String[0];
}
for (int i = 0; i < files.length; i++) {
File file = new File(dir, files[i]);
if (file.isDirectory()) {
deleteDir(file);
} else {
file.delete();
}
}
dir.delete();
}
Delete the specified directory, including all of its contents and
subdirectories recursively. |
protected boolean filter(String name) {
if (name == null)
return false;
// Looking up the package
String packageName = null;
int pos = name.lastIndexOf('.");
if (pos != -1)
packageName = name.substring(0, pos);
else
return false;
for (int i = 0; i < packageTriggers.length; i++) {
if (packageName.startsWith(packageTriggers[i]))
return true;
}
return false;
}
|
public Class findClass(String name) throws ClassNotFoundException {
if (log.isDebugEnabled())
log.debug(" findClass(" + name + ")");
// Cannot load anything from local repositories if class loader is stopped
if (!started) {
throw new ClassNotFoundException(name);
}
// (1) Permission to define this class when using a SecurityManager
if (securityManager != null) {
int i = name.lastIndexOf('.");
if (i >= 0) {
try {
if (log.isTraceEnabled())
log.trace(" securityManager.checkPackageDefinition");
securityManager.checkPackageDefinition(name.substring(0,i));
} catch (Exception se) {
if (log.isTraceEnabled())
log.trace(" -- >Exception-- >ClassNotFoundException", se);
throw new ClassNotFoundException(name, se);
}
}
}
// Ask our superclass to locate this class, if possible
// (throws ClassNotFoundException if it is not found)
Class clazz = null;
try {
if (log.isTraceEnabled())
log.trace(" findClassInternal(" + name + ")");
try {
clazz = findClassInternal(name);
} catch(ClassNotFoundException cnfe) {
if (!hasExternalRepositories) {
throw cnfe;
}
} catch(AccessControlException ace) {
throw new ClassNotFoundException(name, ace);
} catch (RuntimeException e) {
if (log.isTraceEnabled())
log.trace(" -- >RuntimeException Rethrown", e);
throw e;
}
if ((clazz == null) && hasExternalRepositories) {
try {
synchronized (this) {
clazz = super.findClass(name);
}
} catch(AccessControlException ace) {
throw new ClassNotFoundException(name, ace);
} catch (RuntimeException e) {
if (log.isTraceEnabled())
log.trace(" -- >RuntimeException Rethrown", e);
throw e;
}
}
if (clazz == null) {
if (log.isDebugEnabled())
log.debug(" -- > Returning ClassNotFoundException");
throw new ClassNotFoundException(name);
}
} catch (ClassNotFoundException e) {
if (log.isTraceEnabled())
log.trace(" -- > Passing on ClassNotFoundException");
throw e;
}
// Return the class we have located
if (log.isTraceEnabled())
log.debug(" Returning class " + clazz);
if ((log.isTraceEnabled()) && (clazz != null))
log.debug(" Loaded by " + clazz.getClassLoader());
return (clazz);
}
Find the specified class in our local repositories, if possible. If
not found, throw ClassNotFoundException. |
protected Class findClassInternal(String name) throws ClassNotFoundException {
if (!validate(name))
throw new ClassNotFoundException(name);
String tempPath = name.replace('.", '/");
String classPath = tempPath + ".class";
ResourceEntry entry = null;
entry = findResourceInternal(name, classPath);
if (entry == null)
throw new ClassNotFoundException(name);
Class clazz = entry.loadedClass;
if (clazz != null)
return clazz;
synchronized (this) {
if (entry.binaryContent == null && entry.loadedClass == null)
throw new ClassNotFoundException(name);
// Looking up the package
String packageName = null;
int pos = name.lastIndexOf('.");
if (pos != -1)
packageName = name.substring(0, pos);
Package pkg = null;
if (packageName != null) {
pkg = getPackage(packageName);
// Define the package (if null)
if (pkg == null) {
try {
if (entry.manifest == null) {
definePackage(packageName, null, null, null, null,
null, null, null);
} else {
definePackage(packageName, entry.manifest,
entry.codeBase);
}
} catch (IllegalArgumentException e) {
// Ignore: normal error due to dual definition of package
}
pkg = getPackage(packageName);
}
}
if (securityManager != null) {
// Checking sealing
if (pkg != null) {
boolean sealCheck = true;
if (pkg.isSealed()) {
sealCheck = pkg.isSealed(entry.codeBase);
} else {
sealCheck = (entry.manifest == null)
|| !isPackageSealed(packageName, entry.manifest);
}
if (!sealCheck)
throw new SecurityException
("Sealing violation loading " + name + " : Package "
+ packageName + " is sealed.");
}
}
if (entry.loadedClass == null) {
clazz = defineClass(name, entry.binaryContent, 0,
entry.binaryContent.length,
new CodeSource(entry.codeBase, entry.certificates));
entry.loadedClass = clazz;
entry.binaryContent = null;
entry.source = null;
entry.codeBase = null;
entry.manifest = null;
entry.certificates = null;
} else {
clazz = entry.loadedClass;
}
}
return clazz;
}
Find specified class in local repositories. |
public LifecycleListener[] findLifecycleListeners() {
return new LifecycleListener[0];
}
Get the lifecycle listeners associated with this lifecycle. If this
Lifecycle has no listeners registered, a zero-length array is returned. |
protected Class findLoadedClass0(String name) {
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
if (entry != null) {
return entry.loadedClass;
}
return (null); // FIXME - findLoadedResource()
}
Finds the class with the given name if it has previously been
loaded and cached by this class loader, and return the Class object.
If this class has not been cached, return null. |
protected InputStream findLoadedResource(String name) {
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
if (entry != null) {
if (entry.binaryContent != null)
return new ByteArrayInputStream(entry.binaryContent);
}
return (null);
}
Finds the resource with the given name if it has previously been
loaded and cached by this class loader, and return an input stream
to the resource data. If this resource has not been cached, return
null. |
public String[] findRepositories() {
return ((String[])repositories.clone());
}
Return a String array of the current repositories for this class
loader. If there are no repositories, a zero-length array is
returned.For security reason, returns a clone of the Array (since
String are immutable). |
public URL findResource(String name) {
if (log.isDebugEnabled())
log.debug(" findResource(" + name + ")");
URL url = null;
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
if (entry == null) {
entry = findResourceInternal(name, name);
}
if (entry != null) {
url = entry.source;
}
if ((url == null) && hasExternalRepositories)
url = super.findResource(name);
if (log.isDebugEnabled()) {
if (url != null)
log.debug(" -- > Returning '" + url.toString() + "'");
else
log.debug(" -- > Resource not found, returning null");
}
return (url);
}
Find the specified resource in our local repository, and return a
URL refering to it, or null if this resource
cannot be found. |
protected ResourceEntry findResourceInternal(File file,
String path) {
ResourceEntry entry = new ResourceEntry();
try {
entry.source = getURI(new File(file, path));
entry.codeBase = getURL(new File(file, path), false);
} catch (MalformedURLException e) {
return null;
}
return entry;
}
Find specified resource in local repositories. This block
will execute under an AccessControl.doPrivilege block. |
protected ResourceEntry findResourceInternal(String name,
String path) {
if (!started) {
log.info(sm.getString("webappClassLoader.stopped", name));
return null;
}
if ((name == null) || (path == null))
return null;
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
if (entry != null)
return entry;
int contentLength = -1;
InputStream binaryStream = null;
int jarFilesLength = jarFiles.length;
int repositoriesLength = repositories.length;
int i;
Resource resource = null;
boolean fileNeedConvert = false;
for (i = 0; (entry == null) && (i < repositoriesLength); i++) {
try {
String fullPath = repositories[i] + path;
Object lookupResult = resources.lookup(fullPath);
if (lookupResult instanceof Resource) {
resource = (Resource) lookupResult;
}
// Note : Not getting an exception here means the resource was
// found
if (securityManager != null) {
PrivilegedAction dp =
new PrivilegedFindResource(files[i], path);
entry = (ResourceEntry)AccessController.doPrivileged(dp);
} else {
entry = findResourceInternal(files[i], path);
}
ResourceAttributes attributes =
(ResourceAttributes) resources.getAttributes(fullPath);
contentLength = (int) attributes.getContentLength();
entry.lastModified = attributes.getLastModified();
if (resource != null) {
try {
binaryStream = resource.streamContent();
} catch (IOException e) {
return null;
}
if (needConvert) {
if (path.endsWith(".properties")) {
fileNeedConvert = true;
}
}
// Register the full path for modification checking
// Note: Only syncing on a 'constant' object is needed
synchronized (allPermission) {
int j;
long[] result2 =
new long[lastModifiedDates.length + 1];
for (j = 0; j < lastModifiedDates.length; j++) {
result2[j] = lastModifiedDates[j];
}
result2[lastModifiedDates.length] = entry.lastModified;
lastModifiedDates = result2;
String[] result = new String[paths.length + 1];
for (j = 0; j < paths.length; j++) {
result[j] = paths[j];
}
result[paths.length] = fullPath;
paths = result;
}
}
} catch (NamingException e) {
}
}
if ((entry == null) && (notFoundResources.containsKey(name)))
return null;
JarEntry jarEntry = null;
synchronized (jarFiles) {
if (!openJARs()) {
return null;
}
for (i = 0; (entry == null) && (i < jarFilesLength); i++) {
jarEntry = jarFiles[i].getJarEntry(path);
if (jarEntry != null) {
entry = new ResourceEntry();
try {
entry.codeBase = getURL(jarRealFiles[i], false);
String jarFakeUrl = getURI(jarRealFiles[i]).toString();
jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path;
entry.source = new URL(jarFakeUrl);
entry.lastModified = jarRealFiles[i].lastModified();
} catch (MalformedURLException e) {
return null;
}
contentLength = (int) jarEntry.getSize();
try {
entry.manifest = jarFiles[i].getManifest();
binaryStream = jarFiles[i].getInputStream(jarEntry);
} catch (IOException e) {
return null;
}
// Extract resources contained in JAR to the workdir
if (antiJARLocking && !(path.endsWith(".class"))) {
byte[] buf = new byte[1024];
File resourceFile = new File
(loaderDir, jarEntry.getName());
if (!resourceFile.exists()) {
Enumeration entries = jarFiles[i].entries();
while (entries.hasMoreElements()) {
JarEntry jarEntry2 =
(JarEntry) entries.nextElement();
if (!(jarEntry2.isDirectory())
&& (!jarEntry2.getName().endsWith
(".class"))) {
resourceFile = new File
(loaderDir, jarEntry2.getName());
resourceFile.getParentFile().mkdirs();
FileOutputStream os = null;
InputStream is = null;
try {
is = jarFiles[i].getInputStream
(jarEntry2);
os = new FileOutputStream
(resourceFile);
while (true) {
int n = is.read(buf);
if (n < = 0) {
break;
}
os.write(buf, 0, n);
}
} catch (IOException e) {
// Ignore
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
}
}
}
}
}
}
}
}
if (entry == null) {
synchronized (notFoundResources) {
notFoundResources.put(name, name);
}
return null;
}
if (binaryStream != null) {
byte[] binaryContent = new byte[contentLength];
int pos = 0;
try {
while (true) {
int n = binaryStream.read(binaryContent, pos,
binaryContent.length - pos);
if (n < = 0)
break;
pos += n;
}
binaryStream.close();
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
if (fileNeedConvert) {
String str = new String(binaryContent,0,pos);
try {
binaryContent = str.getBytes("UTF-8");
} catch (Exception e) {
return null;
}
}
entry.binaryContent = binaryContent;
// The certificates are only available after the JarEntry
// associated input stream has been fully read
if (jarEntry != null) {
entry.certificates = jarEntry.getCertificates();
}
}
}
// Add the entry in the local resource repository
synchronized (resourceEntries) {
// Ensures that all the threads which may be in a race to load
// a particular class all end up with the same ResourceEntry
// instance
ResourceEntry entry2 = (ResourceEntry) resourceEntries.get(name);
if (entry2 == null) {
resourceEntries.put(name, entry);
} else {
entry = entry2;
}
}
return entry;
}
Find specified resource in local repositories. |
public Enumeration findResources(String name) throws IOException {
if (log.isDebugEnabled())
log.debug(" findResources(" + name + ")");
Vector result = new Vector();
int jarFilesLength = jarFiles.length;
int repositoriesLength = repositories.length;
int i;
// Looking at the repositories
for (i = 0; i < repositoriesLength; i++) {
try {
String fullPath = repositories[i] + name;
resources.lookup(fullPath);
// Note : Not getting an exception here means the resource was
// found
try {
result.addElement(getURI(new File(files[i], name)));
} catch (MalformedURLException e) {
// Ignore
}
} catch (NamingException e) {
}
}
// Looking at the JAR files
synchronized (jarFiles) {
if (openJARs()) {
for (i = 0; i < jarFilesLength; i++) {
JarEntry jarEntry = jarFiles[i].getJarEntry(name);
if (jarEntry != null) {
try {
String jarFakeUrl = getURI(jarRealFiles[i]).toString();
jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name;
result.addElement(new URL(jarFakeUrl));
} catch (MalformedURLException e) {
// Ignore
}
}
}
}
}
// Adding the results of a call to the superclass
if (hasExternalRepositories) {
Enumeration otherResourcePaths = super.findResources(name);
while (otherResourcePaths.hasMoreElements()) {
result.addElement(otherResourcePaths.nextElement());
}
}
return result.elements();
}
Return an enumeration of URLs representing all of the
resources with the given name. If no resources with this name are
found, return an empty enumeration. |
public boolean getAntiJARLocking() {
return antiJARLocking;
}
|
public boolean getDelegate() {
return (this.delegate);
}
Return the "delegate first" flag for this class loader. |
public String getJarPath() {
return this.jarPath;
}
|
protected PermissionCollection getPermissions(CodeSource codeSource) {
String codeUrl = codeSource.getLocation().toString();
PermissionCollection pc;
if ((pc = (PermissionCollection)loaderPC.get(codeUrl)) == null) {
pc = super.getPermissions(codeSource);
if (pc != null) {
Iterator perms = permissionList.iterator();
while (perms.hasNext()) {
Permission p = (Permission)perms.next();
pc.add(p);
}
loaderPC.put(codeUrl,pc);
}
}
return (pc);
}
Get the Permissions for a CodeSource. If this instance
of WebappClassLoader is for a web application context,
add read FilePermission or JndiPermissions for the base
directory (if unpacked),
the context URL, and jar file resources. |
public URL getResource(String name) {
if (log.isDebugEnabled())
log.debug("getResource(" + name + ")");
URL url = null;
// (1) Delegate to parent if requested
if (delegate) {
if (log.isDebugEnabled())
log.debug(" Delegating to parent classloader " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
url = loader.getResource(name);
if (url != null) {
if (log.isDebugEnabled())
log.debug(" -- > Returning '" + url.toString() + "'");
return (url);
}
}
// (2) Search local repositories
url = findResource(name);
if (url != null) {
// Locating the repository for special handling in the case
// of a JAR
if (antiJARLocking) {
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
try {
String repository = entry.codeBase.toString();
if ((repository.endsWith(".jar"))
&& (!(name.endsWith(".class")))) {
// Copy binary content to the work directory if not present
File resourceFile = new File(loaderDir, name);
url = getURI(resourceFile);
}
} catch (Exception e) {
// Ignore
}
}
if (log.isDebugEnabled())
log.debug(" -- > Returning '" + url.toString() + "'");
return (url);
}
// (3) Delegate to parent unconditionally if not already attempted
if( !delegate ) {
ClassLoader loader = parent;
if (loader == null)
loader = system;
url = loader.getResource(name);
if (url != null) {
if (log.isDebugEnabled())
log.debug(" -- > Returning '" + url.toString() + "'");
return (url);
}
}
// (4) Resource was not found
if (log.isDebugEnabled())
log.debug(" -- > Resource not found, returning null");
return (null);
}
Find the resource with the given name. A resource is some data
(images, audio, text, etc.) that can be accessed by class code in a
way that is independent of the location of the code. The name of a
resource is a "/"-separated path name that identifies the resource.
If the resource cannot be found, return null.
This method searches according to the following algorithm, returning
as soon as it finds the appropriate URL. If the resource cannot be
found, returns null.
- If the
delegate property is set to true,
call the getResource() method of the parent class
loader, if any.
- Call
findResource() to find this resource in our
locally defined repositories.
- Call the
getResource() method of the parent class
loader, if any.
|
public InputStream getResourceAsStream(String name) {
if (log.isDebugEnabled())
log.debug("getResourceAsStream(" + name + ")");
InputStream stream = null;
// (0) Check for a cached copy of this resource
stream = findLoadedResource(name);
if (stream != null) {
if (log.isDebugEnabled())
log.debug(" -- > Returning stream from cache");
return (stream);
}
// (1) Delegate to parent if requested
if (delegate) {
if (log.isDebugEnabled())
log.debug(" Delegating to parent classloader " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
stream = loader.getResourceAsStream(name);
if (stream != null) {
// FIXME - cache???
if (log.isDebugEnabled())
log.debug(" -- > Returning stream from parent");
return (stream);
}
}
// (2) Search local repositories
if (log.isDebugEnabled())
log.debug(" Searching local repositories");
URL url = findResource(name);
if (url != null) {
// FIXME - cache???
if (log.isDebugEnabled())
log.debug(" -- > Returning stream from local");
stream = findLoadedResource(name);
try {
if (hasExternalRepositories && (stream == null))
stream = url.openStream();
} catch (IOException e) {
; // Ignore
}
if (stream != null)
return (stream);
}
// (3) Delegate to parent unconditionally
if (!delegate) {
if (log.isDebugEnabled())
log.debug(" Delegating to parent classloader unconditionally " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
stream = loader.getResourceAsStream(name);
if (stream != null) {
// FIXME - cache???
if (log.isDebugEnabled())
log.debug(" -- > Returning stream from parent");
return (stream);
}
}
// (4) Resource was not found
if (log.isDebugEnabled())
log.debug(" -- > Resource not found, returning null");
return (null);
}
Find the resource with the given name, and return an input stream
that can be used for reading it. The search order is as described
for getResource(), after checking to see if the resource
data has been previously cached. If the resource cannot be found,
return null. |
public DirContext getResources() {
// ------------------------------------------------------------- Properties
return this.resources;
}
Get associated resources. |
protected URL getURI(File file) throws MalformedURLException {
File realFile = file;
try {
realFile = realFile.getCanonicalFile();
} catch (IOException e) {
// Ignore
}
return realFile.toURI().toURL();
}
|
protected URL getURL(File file,
boolean encoded) throws MalformedURLException {
File realFile = file;
try {
realFile = realFile.getCanonicalFile();
} catch (IOException e) {
// Ignore
}
if(encoded) {
return getURI(realFile);
} else {
return realFile.toURL();
}
}
|
public URL[] getURLs() {
if (repositoryURLs != null) {
return repositoryURLs;
}
URL[] external = super.getURLs();
int filesLength = files.length;
int jarFilesLength = jarRealFiles.length;
int length = filesLength + jarFilesLength + external.length;
int i;
try {
URL[] urls = new URL[length];
for (i = 0; i < length; i++) {
if (i < filesLength) {
urls[i] = getURL(files[i], true);
} else if (i < filesLength + jarFilesLength) {
urls[i] = getURL(jarRealFiles[i - filesLength], true);
} else {
urls[i] = external[i - filesLength - jarFilesLength];
}
}
repositoryURLs = urls;
} catch (MalformedURLException e) {
repositoryURLs = new URL[0];
}
return repositoryURLs;
}
Returns the search path of URLs for loading classes and resources.
This includes the original list of URLs specified to the constructor,
along with any URLs subsequently appended by the addURL() method. |
protected boolean isPackageSealed(String name,
Manifest man) {
String path = name.replace('.", '/") + '/";
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);
}
Returns true if the specified package name is sealed according to the
given manifest. |
public Class loadClass(String name) throws ClassNotFoundException {
return (loadClass(name, false));
}
Load the class with the specified name. This method searches for
classes in the same manner as loadClass(String, boolean)
with false as the second argument. |
public Class loadClass(String name,
boolean resolve) throws ClassNotFoundException {
if (log.isDebugEnabled())
log.debug("loadClass(" + name + ", " + resolve + ")");
Class clazz = null;
// Log access to stopped classloader
if (!started) {
try {
throw new IllegalStateException();
} catch (IllegalStateException e) {
log.info(sm.getString("webappClassLoader.stopped", name), e);
}
}
// (0) Check our previously loaded local class cache
clazz = findLoadedClass0(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (0.1) Check our previously loaded class cache
clazz = findLoadedClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (0.2) Try loading the class with the system class loader, to prevent
// the webapp from overriding J2SE classes
try {
clazz = system.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
// Ignore
}
// (0.5) Permission to access this class when using a SecurityManager
if (securityManager != null) {
int i = name.lastIndexOf('.");
if (i >= 0) {
try {
securityManager.checkPackageAccess(name.substring(0,i));
} catch (SecurityException se) {
String error = "Security Violation, attempt to use " +
"Restricted Class: " + name;
log.info(error, se);
throw new ClassNotFoundException(error, se);
}
}
}
boolean delegateLoad = delegate || filter(name);
// (1) Delegate to our parent if requested
if (delegateLoad) {
if (log.isDebugEnabled())
log.debug(" Delegating to parent classloader1 " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
// (2) Search local repositories
if (log.isDebugEnabled())
log.debug(" Searching local repositories");
try {
clazz = findClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Loading class from local repository");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
// (3) Delegate to parent unconditionally
if (!delegateLoad) {
if (log.isDebugEnabled())
log.debug(" Delegating to parent classloader at end: " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
throw new ClassNotFoundException(name);
}
Load the class with the specified name, searching using the following
algorithm until it finds and returns the class. If the class cannot
be found, returns ClassNotFoundException.
- Call
findLoadedClass(String) to check if the
class has already been loaded. If it has, the same
Class object is returned.
- If the
delegate property is set to true,
call the loadClass() method of the parent class
loader, if any.
- Call
findClass() to find this class in our locally
defined repositories.
- Call the
loadClass() method of our parent
class loader, if any.
If the class was found using the above steps, and the
resolve flag is true, this method will then
call resolveClass(Class) on the resulting Class object. |
protected boolean loadedByThisOrChild(Class clazz) {
boolean result = false;
for (ClassLoader classLoader = clazz.getClassLoader();
null != classLoader; classLoader = classLoader.getParent()) {
if (classLoader.equals(this)) {
result = true;
break;
}
}
return result;
}
Determine whether a class was loaded by this class loader or one of
its child class loaders. |
public boolean modified() {
if (log.isDebugEnabled())
log.debug("modified()");
// Checking for modified loaded resources
int length = paths.length;
// A rare race condition can occur in the updates of the two arrays
// It's totally ok if the latest class added is not checked (it will
// be checked the next time
int length2 = lastModifiedDates.length;
if (length > length2)
length = length2;
for (int i = 0; i < length; i++) {
try {
long lastModified =
((ResourceAttributes) resources.getAttributes(paths[i]))
.getLastModified();
if (lastModified != lastModifiedDates[i]) {
if( log.isDebugEnabled() )
log.debug(" Resource '" + paths[i]
+ "' was modified; Date is now: "
+ new java.util.Date(lastModified) + " Was: "
+ new java.util.Date(lastModifiedDates[i]));
return (true);
}
} catch (NamingException e) {
log.error(" Resource '" + paths[i] + "' is missing");
return (true);
}
}
length = jarNames.length;
// Check if JARs have been added or removed
if (getJarPath() != null) {
try {
NamingEnumeration enumeration = resources.listBindings(getJarPath());
int i = 0;
while (enumeration.hasMoreElements() && (i < length)) {
NameClassPair ncPair = (NameClassPair) enumeration.nextElement();
String name = ncPair.getName();
// Ignore non JARs present in the lib folder
if (!name.endsWith(".jar"))
continue;
if (!name.equals(jarNames[i])) {
// Missing JAR
log.info(" Additional JARs have been added : '"
+ name + "'");
return (true);
}
i++;
}
if (enumeration.hasMoreElements()) {
while (enumeration.hasMoreElements()) {
NameClassPair ncPair =
(NameClassPair) enumeration.nextElement();
String name = ncPair.getName();
// Additional non-JAR files are allowed
if (name.endsWith(".jar")) {
// There was more JARs
log.info(" Additional JARs have been added");
return (true);
}
}
} else if (i < jarNames.length) {
// There was less JARs
log.info(" Additional JARs have been added");
return (true);
}
} catch (NamingException e) {
if (log.isDebugEnabled())
log.debug(" Failed tracking modifications of '"
+ getJarPath() + "'");
} catch (ClassCastException e) {
log.error(" Failed tracking modifications of '"
+ getJarPath() + "' : " + e.getMessage());
}
}
// No classes have been modified
return (false);
}
Have one or more classes or resources been modified so that a reload
is appropriate? |
protected void nullInstance(Object instance) {
if (instance == null) {
return;
}
Field[] fields = instance.getClass().getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
int mods = field.getModifiers();
if (field.getType().isPrimitive()
|| (field.getName().indexOf("$") != -1)) {
continue;
}
try {
field.setAccessible(true);
if (Modifier.isStatic(mods) && Modifier.isFinal(mods)) {
// Doing something recursively is too risky
continue;
} else {
Object value = field.get(instance);
if (null != value) {
Class valueClass = value.getClass();
if (!loadedByThisOrChild(valueClass)) {
if (log.isDebugEnabled()) {
log.debug("Not setting field " + field.getName() +
" to null in object of class " +
instance.getClass().getName() +
" because the referenced object was of type " +
valueClass.getName() +
" which was not loaded by this WebappClassLoader.");
}
} else {
field.set(instance, null);
if (log.isDebugEnabled()) {
log.debug("Set field " + field.getName()
+ " to null in class " + instance.getClass().getName());
}
}
}
}
} catch (Throwable t) {
if (log.isDebugEnabled()) {
log.debug("Could not set field " + field.getName()
+ " to null in object instance of class "
+ instance.getClass().getName(), t);
}
}
}
}
|
protected boolean openJARs() {
if (started && (jarFiles.length > 0)) {
lastJarAccessed = System.currentTimeMillis();
if (jarFiles[0] == null) {
for (int i = 0; i < jarFiles.length; i++) {
try {
jarFiles[i] = new JarFile(jarRealFiles[i]);
} catch (IOException e) {
if (log.isDebugEnabled()) {
log.debug("Failed to open JAR", e);
}
return false;
}
}
}
}
return true;
}
Used to periodically signal to the classloader to release JAR resources. |
protected void refreshPolicy() {
try {
// The policy file may have been modified to adjust
// permissions, so we're reloading it when loading or
// reloading a Context
Policy policy = Policy.getPolicy();
policy.refresh();
} catch (AccessControlException e) {
// Some policy files may restrict this, even for the core,
// so this exception is ignored
}
}
Refresh the system policy file, to pick up eventual changes. |
public void removeLifecycleListener(LifecycleListener listener) {
}
Remove a lifecycle event listener from this component. |
public void setAntiJARLocking(boolean antiJARLocking) {
this.antiJARLocking = antiJARLocking;
}
|
public void setDelegate(boolean delegate) {
this.delegate = delegate;
}
Set the "delegate first" flag for this class loader. |
public void setJarPath(String jarPath) {
this.jarPath = jarPath;
}
|
protected void setParentClassLoader(ClassLoader pcl) {
parent = pcl;
}
Utility method for use in subclasses.
Must be called before Lifecycle methods to have any effect. |
public void setResources(DirContext resources) {
this.resources = resources;
}
Set associated resources. |
public void setWorkDir(File workDir) {
this.loaderDir = new File(workDir, "loader");
}
Change the work directory. |
public void start() throws LifecycleException {
started = true;
String encoding = null;
try {
encoding = System.getProperty("file.encoding");
} catch (Exception e) {
return;
}
if (encoding.indexOf("EBCDIC")!=-1) {
needConvert = true;
}
}
|
public void stop() throws LifecycleException {
// Clearing references should be done before setting started to
// false, due to possible side effects
clearReferences();
started = false;
int length = files.length;
for (int i = 0; i < length; i++) {
files[i] = null;
}
length = jarFiles.length;
for (int i = 0; i < length; i++) {
try {
if (jarFiles[i] != null) {
jarFiles[i].close();
}
} catch (IOException e) {
// Ignore
}
jarFiles[i] = null;
}
notFoundResources.clear();
resourceEntries.clear();
resources = null;
repositories = null;
repositoryURLs = null;
files = null;
jarFiles = null;
jarRealFiles = null;
jarPath = null;
jarNames = null;
lastModifiedDates = null;
paths = null;
hasExternalRepositories = false;
parent = null;
permissionList.clear();
loaderPC.clear();
if (loaderDir != null) {
deleteDir(loaderDir);
}
}
|
public String toString() {
StringBuffer sb = new StringBuffer("WebappClassLoader\r\n");
sb.append(" delegate: ");
sb.append(delegate);
sb.append("\r\n");
sb.append(" repositories:\r\n");
if (repositories != null) {
for (int i = 0; i < repositories.length; i++) {
sb.append(" ");
sb.append(repositories[i]);
sb.append("\r\n");
}
}
if (this.parent != null) {
sb.append("---------- > Parent Classloader:\r\n");
sb.append(this.parent.toString());
sb.append("\r\n");
}
return (sb.toString());
}
Render a String representation of this object. |
protected boolean validate(String name) {
if (name == null)
return false;
if (name.startsWith("java."))
return false;
return true;
}
Validate a classname. As per SRV.9.7.2, we must restict loading of
classes from J2SE (java.*) and classes of the servlet API
(javax.servlet.*). That should enhance robustness and prevent a number
of user error (where an older version of servlet.jar would be present
in /WEB-INF/lib). |
protected boolean validateJarFile(File jarfile) throws IOException {
if (triggers == null)
return (true);
JarFile jarFile = new JarFile(jarfile);
for (int i = 0; i < triggers.length; i++) {
Class clazz = null;
try {
if (parent != null) {
clazz = parent.loadClass(triggers[i]);
} else {
clazz = Class.forName(triggers[i]);
}
} catch (Throwable t) {
clazz = null;
}
if (clazz == null)
continue;
String name = triggers[i].replace('.", '/") + ".class";
if (log.isDebugEnabled())
log.debug(" Checking for " + name);
JarEntry jarEntry = jarFile.getJarEntry(name);
if (jarEntry != null) {
log.info("validateJarFile(" + jarfile +
") - jar not loaded. See Servlet Spec 2.3, "
+ "section 9.7.2. Offending class: " + name);
jarFile.close();
return (false);
}
}
jarFile.close();
return (true);
}
Check the specified JAR file, and return true if it does
not contain any of the trigger classes. |