/* | |
* 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.cdi.core.api.util; | |
import javax.enterprise.inject.Typed; | |
import java.security.AccessController; | |
import java.security.PrivilegedAction; | |
import java.util.jar.Manifest; | |
import java.util.jar.Attributes; | |
import java.net.URL; | |
/** | |
* Util methods for classes, {@link ClassLoader} and {@link Manifest} handling | |
*/ | |
@Typed() | |
public abstract class ClassUtils | |
{ | |
/** | |
* Constructor which prevents the instantiation of this class | |
*/ | |
private ClassUtils() | |
{ | |
// prevent instantiation | |
} | |
/** | |
* Detect the right ClassLoader. | |
* The lookup order is determined by: | |
* <ol> | |
* <li>ContextClassLoader of the current Thread</li> | |
* <li>ClassLoader of the given Object 'o'</li> | |
* <li>ClassLoader of this very ClassUtils class</li> | |
* </ol> | |
* | |
* @param o if not <code>null</code> it may get used to detect the classloader. | |
* @return The {@link ClassLoader} which should get used to create new instances | |
*/ | |
public static ClassLoader getClassLoader(Object o) | |
{ | |
if (System.getSecurityManager() != null) | |
{ | |
return AccessController.doPrivileged(new GetClassLoaderAction(o)); | |
} | |
else | |
{ | |
return getClassLoaderInternal(o); | |
} | |
} | |
static class GetClassLoaderAction implements PrivilegedAction<ClassLoader> | |
{ | |
private Object object; | |
GetClassLoaderAction(Object object) | |
{ | |
this.object = object; | |
} | |
@Override | |
public ClassLoader run() | |
{ | |
try | |
{ | |
return getClassLoaderInternal(object); | |
} | |
catch (Exception e) | |
{ | |
return null; | |
} | |
} | |
} | |
private static ClassLoader getClassLoaderInternal(Object o) | |
{ | |
ClassLoader loader = Thread.currentThread().getContextClassLoader(); | |
if (loader == null && o != null) | |
{ | |
loader = o.getClass().getClassLoader(); | |
} | |
if (loader == null) | |
{ | |
loader = ClassUtils.class.getClassLoader(); | |
} | |
return loader; | |
} | |
/** | |
* Tries to load a class based on the given name and interface or abstract class. | |
* @param name name of the concrete class | |
* @param targetType target type (interface or abstract class) | |
* @param <T> current type | |
* @return loaded class or null if it isn't in the classpath | |
*/ | |
public static <T> Class<T> tryToLoadClassForName(String name, Class<T> targetType) | |
{ | |
return (Class<T>) tryToLoadClassForName(name); | |
} | |
/** | |
* Tries to load a class based on the given name | |
* @param name name of the class | |
* @return loaded class or null if it isn't in the classpath | |
*/ | |
public static Class tryToLoadClassForName(String name) | |
{ | |
try | |
{ | |
return loadClassForName(name); | |
} | |
catch (ClassNotFoundException e) | |
{ | |
//do nothing - it's just a try | |
return null; | |
} | |
} | |
/** | |
* Loads class for the given name | |
* @param name name of the class | |
* @return loaded class | |
* @throws ClassNotFoundException if the class can't be loaded | |
*/ | |
public static Class loadClassForName(String name) throws ClassNotFoundException | |
{ | |
try | |
{ | |
// Try WebApp ClassLoader first | |
return Class.forName(name, false, // do not initialize for faster startup | |
getClassLoader(null)); | |
} | |
catch (ClassNotFoundException ignore) | |
{ | |
// fallback: Try ClassLoader for ClassUtils (i.e. the myfaces.jar lib) | |
return Class.forName(name, false, // do not initialize for faster startup | |
ClassUtils.class.getClassLoader()); | |
} | |
} | |
/** | |
* Instantiates a given class via the default constructor | |
* @param targetClass class which should be instantiated | |
* @param <T> current type | |
* @return created instance or null if the instantiation failed | |
*/ | |
public static <T> T tryToInstantiateClass(Class<T> targetClass) | |
{ | |
try | |
{ | |
return targetClass.newInstance(); | |
} | |
catch (Exception e) | |
{ | |
//do nothing - it was just a try | |
} | |
return null; | |
} | |
/** | |
* Tries to instantiate a class for the given name and type via the default constructor | |
* @param className name of the class | |
* @param targetType target type | |
* @param <T> current type | |
* @return created instance or null if the instantiation failed | |
*/ | |
public static <T> T tryToInstantiateClassForName(String className, Class<T> targetType) | |
{ | |
Object result = tryToInstantiateClassForName(className); | |
//noinspection unchecked | |
return result != null ? (T) result : null; | |
} | |
/** | |
* Tries to instantiate a class for the given name via the default constructor | |
* @param className name of the class | |
* @return created instance or null if the instantiation failed | |
*/ | |
public static Object tryToInstantiateClassForName(String className) | |
{ | |
try | |
{ | |
return instantiateClassForName(className); | |
} | |
catch (Exception e) | |
{ | |
//do nothing - it was just a try | |
} | |
return null; | |
} | |
/** | |
* Creates an instance for the given class-name | |
* @param className name of the class which should be instantiated | |
* @return created instance | |
* @throws ClassNotFoundException if the instantiation failed | |
* @throws IllegalAccessException if the instantiation failed | |
* @throws InstantiationException if the instantiation failed | |
*/ | |
public static Object instantiateClassForName(String className) | |
throws ClassNotFoundException, IllegalAccessException, InstantiationException | |
{ | |
return loadClassForName(className).newInstance(); | |
} | |
/** | |
* Reads the version of the jar which contains the given class | |
* @param targetClass class within the jar | |
* @return version-string which has been found in the manifest or null if there is no version information available | |
*/ | |
public static String getJarVersion(Class targetClass) | |
{ | |
String manifestFileLocation = getManifestFileLocationOfClass(targetClass); | |
try | |
{ | |
return new Manifest(new URL(manifestFileLocation).openStream()) | |
.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION); | |
} | |
catch (Exception e) | |
{ | |
return null; | |
} | |
} | |
/** | |
* Reads the VCS revision which was used for creating the jar | |
* @param targetClass class within the jar | |
* @return revision-string which has been found in the manifest or null if there is no information available | |
*/ | |
public static String getRevision(Class targetClass) | |
{ | |
String manifestFileLocation = getManifestFileLocationOfClass(targetClass); | |
try | |
{ | |
return new Manifest(new URL(manifestFileLocation).openStream()) | |
.getMainAttributes().getValue("Revision"); | |
} | |
catch (Exception e) | |
{ | |
return null; | |
} | |
} | |
private static String getManifestFileLocationOfClass(Class targetClass) | |
{ | |
String manifestFileLocation; | |
try | |
{ | |
manifestFileLocation = getManifestLocation(targetClass); | |
} | |
catch (Exception e) | |
{ | |
//in this case we have a proxy | |
manifestFileLocation = getManifestLocation(targetClass.getSuperclass()); | |
} | |
return manifestFileLocation; | |
} | |
private static String getManifestLocation(Class targetClass) | |
{ | |
String classFilePath = targetClass.getCanonicalName().replace('.', '/') + ".class"; | |
String manifestFilePath = "/META-INF/MANIFEST.MF"; | |
String classLocation = targetClass.getResource(targetClass.getSimpleName() + ".class").toString(); | |
return classLocation.substring(0, classLocation.indexOf(classFilePath) - 1) + manifestFilePath; | |
} | |
} |