/*
* Copyright to the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.rioproject.start;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.SecureClassLoader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;
/**
* This class provides useful utilities for creating and
* manipulating class loaders.
*
* @author Sun Microsystems, Inc.
* @author Dennis Reedy
*/
public final class ClassLoaderUtil {
private static final Logger logger = LoggerFactory.getLogger(ClassLoaderUtil.class);
// Private constructor to prevent instantiation
private ClassLoaderUtil() {
}
public static URL[] getClasspathURLs(String classpath) throws IOException, MalformedURLException {
StringTokenizer st = new StringTokenizer(classpath, File.pathSeparator);
URL[] urls = new URL[st.countTokens()];
if (logger.isTraceEnabled())
logger.trace("Create URLs from {}", classpath);
for(int i = 0; st.hasMoreTokens(); ++i) {
String next = st.nextToken();
File f = new File(next);
if (logger.isTraceEnabled())
logger.trace("Created {} from {}", f.getCanonicalFile().toURI().toURL(), next);
urls[i] = f.getCanonicalFile().toURI().toURL();
}
return urls;
}
public static URL[] getCodebaseURLs(String codebase) throws MalformedURLException {
StringTokenizer st = new StringTokenizer(codebase);
URL[] urls = new URL[st.countTokens()];
if (logger.isTraceEnabled())
logger.trace("Create codebase from {}", codebase);
for(int i = 0; st.hasMoreTokens(); ++i) {
urls[i] = new URL(st.nextToken());
}
return urls;
}
/**
* Utility method that retrieves the components making up the class loader
* delegation tree for the current context class loader and returns each
* in an <code>ArrayList</code>.
*
* @return an <code>List</code> instance in which each element of the
* list is one of the components making up the current delegation
* tree.
*/
private static List<ClassLoader> getContextClassLoaderTreeList() {
Thread curThread = Thread.currentThread();
ClassLoader curClassLoader = curThread.getContextClassLoader();
return getClassLoaderTreeList(curClassLoader);
}//end getCurClassLoaderTree
/**
* Utility method that retrieves the components making up the class loader
* delegation tree for the given <code>classloader</code> parameter and
* returns them via an <code>ArrayList</code>.
*
* @param classloader <code>ClassLoader</code> instance whose delegation
* tree is to be retrieved and returned
* @return an <code>List</code> instance in which each element of the
* list is one of the components making up the delegation tree
* of the given class loader.
*/
private static List<ClassLoader> getClassLoaderTreeList(ClassLoader classloader) {
List<ClassLoader> loaderList = new ArrayList<ClassLoader>();
while (classloader != null) {
loaderList.add(classloader);
classloader = classloader.getParent();
}//end loop
loaderList.add(null); //Append boot classloader
Collections.reverse(loaderList);
return loaderList;
}//end getClassLoaderTree
/**
* Utility method that gets the class loader delegation tree for
* the current context class loader. For each class loader in the tree,
* this method displays the locations from which that class loader
* will retrieve and load requested classes.
* <p/>
* This method can be useful when debugging problems related to the
* receipt of exceptions such as <code>ClassNotFoundException</code>.
*/
public static String getContextClassLoaderTree() {
Thread curThread = Thread.currentThread();
ClassLoader curClassLoader = curThread.getContextClassLoader();
return getClassLoaderTree(curClassLoader);
}
/**
* Utility method that gets the class loader delegation tree for
* the given class loader. For each class loader in the tree, this
* method formats the locations from which that class loader will
* retrieve and load requested classes.
* <p/>
* This method can be useful when debugging problems related to the
* receipt of exceptions such as <code>ClassNotFoundException</code>.
*
* @param classloader <code>ClassLoader</code> instance whose delegation tree is to be obtained
*/
public static String getClassLoaderTree(ClassLoader classloader) {
List<ClassLoader> loaderList = getClassLoaderTreeList(classloader);
StringBuilder builder = new StringBuilder();
builder.append("\n");
builder.append("ClassLoader Tree has ").append(loaderList.size()).append(" levels\n");
builder.append(" cl0 -- Boot ClassLoader\n");
ClassLoader curClassLoader;
for (int i = 1; i < loaderList.size(); i++) {
builder.append(" |\n");
curClassLoader = loaderList.get(i);
builder.append(" cl" + i + " -- ClassLoader ").append(curClassLoader).append(": ");
if (curClassLoader instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) (curClassLoader)).getURLs();
if (urls != null) {
builder.append(urls[0]);
for (int j = 1; j < urls.length; j++) {
builder.append(", ").append(urls[j]);
}
} else {
builder.append("null search path");
}
} else {
if (curClassLoader instanceof SecureClassLoader) {
builder.append("is instance of SecureClassLoader");
} else {
builder.append("is unknown ClassLoader type");
}
}
builder.append("\n");
}
builder.append("\n");
return builder.toString();
}
}