forked from arquillian/arquillian-core
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ARQ-1024 Support package, private and super class field/method/contru…
…ctor lookup * Align all SecurityActions
- Loading branch information
1 parent
c5808bb
commit a68916c
Showing
32 changed files
with
4,049 additions
and
922 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
367 changes: 367 additions & 0 deletions
367
container/impl-base/src/main/java/org/jboss/arquillian/container/impl/SecurityActions.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,367 @@ | ||
/* | ||
* JBoss, Home of Professional Open Source | ||
* Copyright 2009, Red Hat Middleware LLC, and individual contributors | ||
* by the @authors tag. See the copyright.txt in the distribution for a | ||
* full listing of individual contributors. | ||
* | ||
* 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.jboss.arquillian.container.impl; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.lang.reflect.Constructor; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.Method; | ||
import java.security.AccessController; | ||
import java.security.PrivilegedAction; | ||
import java.security.PrivilegedActionException; | ||
import java.security.PrivilegedExceptionAction; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
/** | ||
* A set of privileged actions that are not to leak out | ||
* of this package | ||
* | ||
* @version $Revision: $ | ||
*/ | ||
final class SecurityActions | ||
{ | ||
|
||
//-------------------------------------------------------------------------------|| | ||
// Constructor ------------------------------------------------------------------|| | ||
//-------------------------------------------------------------------------------|| | ||
|
||
/** | ||
* No instantiation | ||
*/ | ||
private SecurityActions() | ||
{ | ||
throw new UnsupportedOperationException("No instantiation"); | ||
} | ||
|
||
//-------------------------------------------------------------------------------|| | ||
// Utility Methods --------------------------------------------------------------|| | ||
//-------------------------------------------------------------------------------|| | ||
|
||
/** | ||
* Obtains the Thread Context ClassLoader | ||
*/ | ||
static ClassLoader getThreadContextClassLoader() | ||
{ | ||
return AccessController.doPrivileged(GetTcclAction.INSTANCE); | ||
} | ||
|
||
static boolean isClassPresent(String name) | ||
{ | ||
try | ||
{ | ||
loadClass(name); | ||
return true; | ||
} | ||
catch (Exception e) | ||
{ | ||
return false; | ||
} | ||
} | ||
|
||
static Class<?> loadClass(String className) | ||
{ | ||
try | ||
{ | ||
return Class.forName(className, true, getThreadContextClassLoader()); | ||
} | ||
catch (ClassNotFoundException e) | ||
{ | ||
try | ||
{ | ||
return Class.forName(className, true, SecurityActions.class.getClassLoader()); | ||
} | ||
catch (ClassNotFoundException e2) | ||
{ | ||
throw new RuntimeException("Could not load class " + className, e2); | ||
} | ||
} | ||
} | ||
|
||
static <T> T newInstance(final String className, final Class<?>[] argumentTypes, final Object[] arguments, final Class<T> expectedType) | ||
{ | ||
return newInstance(className, argumentTypes, arguments, expectedType, getThreadContextClassLoader()); | ||
} | ||
|
||
static <T> T newInstance(final String className, final Class<?>[] argumentTypes, final Object[] arguments, final Class<T> expectedType, ClassLoader classLoader) | ||
{ | ||
Class<?> clazz = null; | ||
try | ||
{ | ||
clazz = Class.forName(className, false, classLoader); | ||
} | ||
catch (Exception e) | ||
{ | ||
throw new RuntimeException("Could not load class " + className, e); | ||
} | ||
Object obj = newInstance(clazz, argumentTypes, arguments); | ||
try | ||
{ | ||
return expectedType.cast(obj); | ||
} | ||
catch (Exception e) | ||
{ | ||
throw new RuntimeException("Loaded class " + className + " is not of expected type " + expectedType, e); | ||
} | ||
} | ||
|
||
/** | ||
* Create a new instance by finding a constructor that matches the argumentTypes signature | ||
* using the arguments for instantiation. | ||
* | ||
* @param className Full classname of class to create | ||
* @param argumentTypes The constructor argument types | ||
* @param arguments The constructor arguments | ||
* @return a new instance | ||
* @throws IllegalArgumentException if className, argumentTypes, or arguments are null | ||
* @throws RuntimeException if any exceptions during creation | ||
* @author <a href="mailto:aslak@conduct.no">Aslak Knutsen</a> | ||
* @author <a href="mailto:andrew.rubinger@jboss.org">ALR</a> | ||
*/ | ||
static <T> T newInstance(final Class<T> implClass, final Class<?>[] argumentTypes, final Object[] arguments) | ||
{ | ||
if (implClass == null) | ||
{ | ||
throw new IllegalArgumentException("ImplClass must be specified"); | ||
} | ||
if (argumentTypes == null) | ||
{ | ||
throw new IllegalArgumentException("ArgumentTypes must be specified. Use empty array if no arguments"); | ||
} | ||
if (arguments == null) | ||
{ | ||
throw new IllegalArgumentException("Arguments must be specified. Use empty array if no arguments"); | ||
} | ||
final T obj; | ||
try | ||
{ | ||
Constructor<T> constructor = getConstructor(implClass, argumentTypes); | ||
if(!constructor.isAccessible()) { | ||
constructor.setAccessible(true); | ||
} | ||
obj = constructor.newInstance(arguments); | ||
} | ||
catch (Exception e) | ||
{ | ||
throw new RuntimeException("Could not create new instance of " + implClass, e); | ||
} | ||
|
||
return obj; | ||
} | ||
|
||
/** | ||
* Obtains the Constructor specified from the given Class and argument types | ||
* @param clazz | ||
* @param argumentTypes | ||
* @return | ||
* @throws NoSuchMethodException | ||
*/ | ||
static <T> Constructor<T> getConstructor(final Class<T> clazz, final Class<?>... argumentTypes) | ||
throws NoSuchMethodException | ||
{ | ||
try | ||
{ | ||
return AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<T>>() | ||
{ | ||
public Constructor<T> run() throws NoSuchMethodException | ||
{ | ||
return clazz.getDeclaredConstructor(argumentTypes); | ||
} | ||
}); | ||
} | ||
// Unwrap | ||
catch (final PrivilegedActionException pae) | ||
{ | ||
final Throwable t = pae.getCause(); | ||
// Rethrow | ||
if (t instanceof NoSuchMethodException) | ||
{ | ||
throw (NoSuchMethodException) t; | ||
} | ||
else | ||
{ | ||
// No other checked Exception thrown by Class.getConstructor | ||
try | ||
{ | ||
throw (RuntimeException) t; | ||
} | ||
// Just in case we've really messed up | ||
catch (final ClassCastException cce) | ||
{ | ||
throw new RuntimeException("Obtained unchecked Exception; this code should never be reached", t); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Set a single Field value | ||
* | ||
* @param target The object to set it on | ||
* @param fieldName The field name | ||
* @param value The new value | ||
*/ | ||
public static void setFieldValue(final Class<?> source, final Object target, final String fieldName, final Object value) throws NoSuchFieldException | ||
{ | ||
try | ||
{ | ||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() | ||
{ | ||
@Override | ||
public Void run() throws Exception | ||
{ | ||
Field field = source.getDeclaredField(fieldName); | ||
if(!field.isAccessible()) | ||
{ | ||
field.setAccessible(true); | ||
} | ||
field.set(target, value); | ||
return null; | ||
} | ||
}); | ||
} | ||
// Unwrap | ||
catch (final PrivilegedActionException pae) | ||
{ | ||
final Throwable t = pae.getCause(); | ||
// Rethrow | ||
if (t instanceof NoSuchFieldException) | ||
{ | ||
throw (NoSuchFieldException) t; | ||
} | ||
else | ||
{ | ||
// No other checked Exception thrown by Class.getConstructor | ||
try | ||
{ | ||
throw (RuntimeException) t; | ||
} | ||
// Just in case we've really messed up | ||
catch (final ClassCastException cce) | ||
{ | ||
throw new RuntimeException("Obtained unchecked Exception; this code should never be reached", t); | ||
} | ||
} | ||
} | ||
} | ||
|
||
public static List<Field> getFieldsWithAnnotation(final Class<?> source, final Class<? extends Annotation> annotationClass) | ||
{ | ||
List<Field> declaredAccessableFields = AccessController.doPrivileged(new PrivilegedAction<List<Field>>() | ||
{ | ||
public List<Field> run() | ||
{ | ||
List<Field> foundFields = new ArrayList<Field>(); | ||
Class<?> nextSource = source; | ||
while (nextSource != Object.class) { | ||
for(Field field : nextSource.getDeclaredFields()) | ||
{ | ||
if(field.isAnnotationPresent(annotationClass)) | ||
{ | ||
if(!field.isAccessible()) | ||
{ | ||
field.setAccessible(true); | ||
} | ||
foundFields.add(field); | ||
} | ||
} | ||
nextSource = nextSource.getSuperclass(); | ||
} | ||
return foundFields; | ||
} | ||
}); | ||
return declaredAccessableFields; | ||
} | ||
|
||
public static List<Method> getMethodsWithAnnotation(final Class<?> source, final Class<? extends Annotation> annotationClass) | ||
{ | ||
List<Method> declaredAccessableMethods = AccessController.doPrivileged(new PrivilegedAction<List<Method>>() | ||
{ | ||
public List<Method> run() | ||
{ | ||
List<Method> foundMethods = new ArrayList<Method>(); | ||
Class<?> nextSource = source; | ||
while (nextSource != Object.class) { | ||
for(Method method : nextSource.getDeclaredMethods()) | ||
{ | ||
if(method.isAnnotationPresent(annotationClass)) | ||
{ | ||
if(!method.isAccessible()) | ||
{ | ||
method.setAccessible(true); | ||
} | ||
foundMethods.add(method); | ||
} | ||
} | ||
nextSource = nextSource.getSuperclass(); | ||
} | ||
return foundMethods; | ||
} | ||
}); | ||
return declaredAccessableMethods; | ||
} | ||
|
||
static String getProperty(final String key) { | ||
try { | ||
String value = AccessController.doPrivileged(new PrivilegedExceptionAction<String>() { | ||
public String run() { | ||
return System.getProperty(key); | ||
} | ||
}); | ||
return value; | ||
} | ||
// Unwrap | ||
catch (final PrivilegedActionException pae) { | ||
final Throwable t = pae.getCause(); | ||
// Rethrow | ||
if (t instanceof SecurityException) { | ||
throw (SecurityException) t; | ||
} | ||
if (t instanceof NullPointerException) { | ||
throw (NullPointerException) t; | ||
} else if (t instanceof IllegalArgumentException) { | ||
throw (IllegalArgumentException) t; | ||
} else { | ||
// No other checked Exception thrown by System.getProperty | ||
try { | ||
throw (RuntimeException) t; | ||
} | ||
// Just in case we've really messed up | ||
catch (final ClassCastException cce) { | ||
throw new RuntimeException("Obtained unchecked Exception; this code should never be reached", t); | ||
} | ||
} | ||
} | ||
} | ||
|
||
//-------------------------------------------------------------------------------|| | ||
// Inner Classes ----------------------------------------------------------------|| | ||
//-------------------------------------------------------------------------------|| | ||
|
||
/** | ||
* Single instance to get the TCCL | ||
*/ | ||
private enum GetTcclAction implements PrivilegedAction<ClassLoader> { | ||
INSTANCE; | ||
|
||
public ClassLoader run() | ||
{ | ||
return Thread.currentThread().getContextClassLoader(); | ||
} | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.