blob: 9afe937b346dd3fb6cc0b0ed95b77cf17d767055 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.myfaces.extensions.scripting.core.common.util;
import org.apache.myfaces.extensions.scripting.core.api.ClassLoaderService;
import org.apache.myfaces.extensions.scripting.core.api.WeavingContext;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* <p>Utility class for class loading purposes, e.g. to determine the classpath of a
* class loader hierarchy.</p>
*/
public class ClassLoaderUtils {
/**
* fetches a default classloader service which is responsible of registering
* a classloader into the system
*
* @return the classloading registration service
*/
public static ClassLoaderService getDefaultClassLoaderService() {
Iterator<ClassLoaderService> serviceIt = ServiceLoader.load(ClassLoaderService.class).iterator();
ClassLoaderService finalService = null;
while(serviceIt.hasNext()) {
ClassLoaderService service = serviceIt.next();
if(finalService == null || service.getPriority() > finalService.getPriority()) {
finalService = service;
}
}
return finalService;
}
// ------------------------------------------ Public methods
/**
* CompilationResult
* <p>Returns the default class loader to use.</p>
*
* @return the default class loader to use
*/
public static ClassLoader getDefaultClassLoader() {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
if (classLoader != null) {
return classLoader;
} else {
return ClassLoaderUtils.class.getClassLoader();
}
}
/**
* <p>Determines whether the given class is loadable by the given class loader.</p>
*
* @param className the class you want to check
* @param classLoader the class loader to use for that check
* @return <code>true</code>, if the given class is loadable by the given class loader
*/
public static boolean isClassAvailable(String className, ClassLoader classLoader) {
try {
classLoader.loadClass(className);
return true;
}
catch (Throwable ex) {
return false;
}
}
/**
* <p>Resolves the classpath by walking up the hierachy of class loaders. Assuming
* that we're only dealing with URLClassLoaders it's possible to determine the
* classpath. This method, however, returns the classpath as a String, where each
* classpath entry is separated by a ';', i.e. it returns the classpath in a format
* that Java tools usually expect it to be.</p>
* <p>&nbsp;</p>
* it also adds the additional classpaths issued by our configuration to the list
*
* @param classLoader the class loader which you want to resolve the class path for
* @return the final classpath
*/
public static String buildClasspath(ClassLoader classLoader) {
StringBuilder classpath = new StringBuilder();
URL[] urls = resolveClasspath(classLoader);
for (URL url : urls) {
try
{
classpath.append(URLDecoder.decode(url.getPath(), Charset.defaultCharset().toString()));
// Note that the classpath separator character is platform
// dependent. On Windows systems it's ";" whereas on other
// UNIX systems it's ":".
classpath.append(File.pathSeparatorChar);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
String retVal = classpath.toString();
if (retVal.endsWith(File.pathSeparator)) {
retVal = retVal.substring(0, retVal.length() - 1);
}
return retVal;
}
/**
* <p>Resolves the classpath by walking up the hierarchy of class loaders. Assuming
* that we're only dealing with URLClassLoaders it's possible to determine the
* classpath.</p>
*
* @param parent the class loader which you want to resolve the class path for
* @return the final classpath
*/
public static URL[] resolveClasspath(ClassLoader parent) {
List<URL> classpath = new ArrayList<URL>();
ClassLoader classLoader = parent;
// Walk up the hierachy of class loaders in order to determine the current classpath.
File target = WeavingContext.getInstance().getConfiguration().getCompileTarget();
if (target != null) {
addFile(classpath, target);
}
while (classLoader != null) {
if (classLoader instanceof URLClassLoader) {
URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
URL[] urls = urlClassLoader.getURLs();
if (urls != null) {
classpath.addAll(Arrays.asList(urls));
}
} /*else {
if (logger.isWarnEnabled()) {
logger.warn("Resolving the classpath of the classloader '" + parent + "' - One of its parent class"
+ " loaders is no URLClassLoader '" + classLoader + "', which means it's possible that"
+ " some classpath entries aren't in the final outcome of this method call.");
}
} */
//we disable this warning entirely for now because our own url classloader
//can deal with this properly, due to extra startup context classpath determination
// Inspect the parent class loader next.
classLoader = classLoader.getParent();
}
List<String> additionalClassPaths = WeavingContext.getInstance().getConfiguration().getAdditionalClassPath();
if (!(additionalClassPaths == null || additionalClassPaths.isEmpty())) {
for (String additionalClassPath : additionalClassPaths) {
File additionalPath = new File(additionalClassPath);
addFile(classpath, additionalPath);
}
}
return classpath.toArray(new URL[classpath.size()]);
}
private static void addFile(List<URL> classpath, File additionalPath) {
if (additionalPath.exists()) {
try {
classpath.add(additionalPath.toURI().toURL());
} catch (MalformedURLException e) {
Logger log = Logger.getLogger(ClassLoaderUtils.class.getName());
log.log(Level.SEVERE, "Additionalclasspath wrong url", e);
}
}
}
}