Revision created by MOE tool push_codebase.
[gae.git] / java / src / main / com / google / appengine / tools / development / agent / runtime / Runtime.java
blob922b18084a1d274199aff4dbaad55424895b2ac2
1 // Copyright 2009 Google Inc. All Rights Reserved.
3 package com.google.appengine.tools.development.agent.runtime;
5 import com.google.appengine.tools.development.agent.AppEngineDevAgent;
6 import com.google.appengine.tools.development.agent.impl.Agent;
7 import com.google.apphosting.utils.clearcast.ClearCast;
9 import sun.reflect.Reflection;
11 import java.lang.reflect.AccessibleObject;
12 import java.lang.reflect.Constructor;
13 import java.lang.reflect.Field;
14 import java.lang.reflect.InvocationTargetException;
15 import java.lang.reflect.Member;
16 import java.lang.reflect.Method;
17 import java.lang.reflect.Modifier;
18 import java.security.AccessController;
19 import java.security.PrivilegedAction;
20 import java.security.PrivilegedActionException;
21 import java.security.PrivilegedExceptionAction;
22 import java.util.Set;
24 /**
25 * Provides runtime support for
26 * {@link com.google.appengine.tools.development.agent.AppEngineDevAgent AppEngineDevAgent}.
29 public class Runtime {
31 private static Agent agent = ClearCast.cast(AppEngineDevAgent.getAgent(), Agent.class);
32 private static Set<String> blackList = agent.getBlackList();
34 public static ClassLoader checkParentClassLoader(ClassLoader loader) {
35 ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
36 return loader != null && loader != systemLoader ? loader : Runtime.class.getClassLoader();
39 public static void recordClassLoader(ClassLoader loader) {
40 agent.recordAppClassLoader(loader);
43 public static void reject(String className) {
44 throw new NoClassDefFoundError(className + " is a restricted class. Please see the Google "
45 + " App Engine developer's guide for more details.");
48 /**
49 * This method is only invoked via injected bytecode.
51 * @see RuntimeHelper#checkRestricted(boolean, String, String, String) ;
53 @SuppressWarnings("unused")
54 public static void checkRestricted(boolean violationIsError, String classStr,
55 String callingClassStr, String callingClassCodeSource) {
56 if (System.getProperty("appengine.disableRestrictedCheck") == null) {
57 RuntimeHelper.checkRestricted(
58 violationIsError, classStr, callingClassStr, callingClassCodeSource);
62 private static boolean isBlackListed(Class<?> klass) {
63 String className = klass.getName().replace('.', '/');
64 return blackList.contains(className);
67 private static Class<?> verifyWhiteListed(Member m) throws IllegalAccessException {
68 Class<?> klass = m.getDeclaringClass();
69 if (!isWhiteListed(klass, m)) {
70 throw new IllegalAccessException("Reflection is not allowed on " + m);
72 return klass;
75 private static void verifyReadable(Class<?> caller, Field f, Object target)
76 throws IllegalAccessException {
77 checkAccess(f, target, caller);
78 verifyWhiteListed(f);
81 private static void verifyWritable(Class<?> caller, Field f, Object target)
82 throws IllegalAccessException {
83 checkAccess(f, target, caller);
84 Class<?> klass = verifyWhiteListed(f);
86 if (getClassLoaderPrivileged(klass) == null) {
87 if (!Modifier.isPublic(f.getModifiers())) {
88 throw new IllegalAccessException("Private fields can not be set on JRE classes.");
93 private static ClassLoader getClassLoaderPrivileged(final Class<?> klass) {
94 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
95 @Override
96 public ClassLoader run() {
97 return klass.getClassLoader();
99 });
102 public static Object invoke(Method method, Object target, Object[] args) throws
103 InvocationTargetException, IllegalAccessException {
104 checkAccess(method, target, getImmediateCallerClassPrivileged());
105 verifyWhiteListed(method);
106 AccessibilityModifier am = new AccessibilityModifier(method);
107 try {
108 return method.invoke(target, args);
109 } finally {
110 am.restore();
114 private static Object newInstance_(Class<?> callerClass, Constructor<?> cons, Object[] args)
115 throws InstantiationException, IllegalAccessException, InvocationTargetException {
116 checkAccess(cons, null, callerClass);
117 verifyWhiteListed(cons);
118 AccessibilityModifier am = new AccessibilityModifier(cons);
119 try {
120 return cons.newInstance(args);
121 } finally {
122 am.restore();
126 public static Object newInstance(Constructor<?> cons, Object[] args)
127 throws InstantiationException, IllegalAccessException, InvocationTargetException {
128 return newInstance_(getImmediateCallerClassPrivileged(), cons, args);
131 public static Object newInstance(final Class<?> klass) throws InstantiationException,
132 IllegalAccessException {
133 try {
134 Constructor<?> cons = AccessController.doPrivileged(
135 new PrivilegedExceptionAction<Constructor<?>>() {
136 @Override
137 public Constructor<?> run() throws NoSuchMethodException {
138 return klass.getDeclaredConstructor();
141 return newInstance_(getImmediateCallerClassPrivileged(), cons, new Object[0]);
142 } catch (PrivilegedActionException e) {
143 Throwable t = e.getCause();
144 if (t instanceof NoSuchMethodException) {
145 throw new InstantiationException(t.getMessage());
147 throw new RuntimeException(t);
148 } catch (InvocationTargetException e) {
149 throwAsUnchecked(e.getCause());
150 throw new InstantiationException((e.getCause().getMessage()));
154 public static Object get(final Field f, final Object obj)
155 throws IllegalAccessException, IllegalArgumentException {
156 return verifyAndRun(f, obj, Op.Get, new Action<Object>() {
157 @Override
158 public Object run(Field f, Object target) throws IllegalAccessException {
159 return f.get(target);
164 public static boolean getBoolean(final Field f, final Object obj)
165 throws IllegalAccessException, IllegalArgumentException {
166 return verifyAndRun(f, obj, Op.Get, new Action<Boolean>() {
167 @Override
168 public Boolean run(Field f, Object target) throws IllegalAccessException {
169 return f.getBoolean(target);
174 public static byte getByte(final Field f, final Object obj)
175 throws IllegalAccessException, IllegalArgumentException {
176 return verifyAndRun(f, obj, Op.Get, new Action<Byte>() {
177 @Override
178 public Byte run(Field f, Object target) throws IllegalAccessException {
179 return f.getByte(target);
184 public static char getChar(final Field f, final Object obj)
185 throws IllegalAccessException, IllegalArgumentException {
186 return verifyAndRun(f, obj, Op.Get, new Action<Character>() {
187 @Override
188 public Character run(Field f, Object target) throws IllegalAccessException {
189 return f.getChar(target);
194 public static double getDouble(final Field f, final Object obj)
195 throws IllegalAccessException, IllegalArgumentException {
196 return verifyAndRun(f, obj, Op.Get, new Action<Double>() {
197 @Override
198 public Double run(Field f, Object target) throws IllegalAccessException {
199 return f.getDouble(target);
204 public static float getFloat(final Field f, final Object obj)
205 throws IllegalAccessException, IllegalArgumentException {
206 return verifyAndRun(f, obj, Op.Get, new Action<Float>() {
207 @Override
208 public Float run(Field f, Object target) throws IllegalAccessException {
209 return f.getFloat(target);
214 public static int getInt(final Field f, final Object obj)
215 throws IllegalAccessException, IllegalArgumentException {
216 return verifyAndRun(f, obj, Op.Get, new Action<Integer>() {
217 @Override
218 public Integer run(Field f, Object target) throws IllegalAccessException {
219 return f.getInt(target);
224 public static long getLong(final Field f, final Object obj)
225 throws IllegalAccessException, IllegalArgumentException {
226 return verifyAndRun(f, obj, Op.Get, new Action<Long>() {
227 @Override
228 public Long run(Field f, Object target) throws IllegalAccessException {
229 return f.getLong(target);
234 public static short getShort(final Field f, final Object obj)
235 throws IllegalAccessException, IllegalArgumentException {
236 return verifyAndRun(f, obj, Op.Get, new Action<Short>() {
237 @Override
238 public Short run(Field f, Object target) throws IllegalAccessException {
239 return f.getShort(target);
244 public static void set(Field f, Object obj, final Object value)
245 throws IllegalAccessException, IllegalArgumentException {
246 verifyAndRun(f, obj, Op.Set, new Action<Object>() {
247 @Override
248 public Object run(Field f, Object target) throws IllegalAccessException {
249 f.set(target, value);
250 return null;
255 public static void setBoolean(Field f, Object obj, final boolean value)
256 throws IllegalAccessException, IllegalArgumentException {
257 verifyAndRun(f, obj, Op.Set, new Action<Object>() {
258 @Override
259 public Object run(Field f, Object target) throws IllegalAccessException {
260 f.setBoolean(target, value);
261 return null;
266 public static void setByte(Field f, Object obj, final byte value)
267 throws IllegalAccessException, IllegalArgumentException {
268 verifyAndRun(f, obj, Op.Set, new Action<Object>() {
269 @Override
270 public Object run(Field f, Object target) throws IllegalAccessException {
271 f.setByte(target, value);
272 return null;
277 public static void setChar(Field f, Object obj, final char value)
278 throws IllegalAccessException, IllegalArgumentException {
279 verifyAndRun(f, obj, Op.Set, new Action<Object>() {
280 @Override
281 public Object run(Field f, Object target) throws IllegalAccessException {
282 f.setChar(target, value);
283 return null;
288 public static void setDouble(Field f, Object obj, final double value)
289 throws IllegalAccessException, IllegalArgumentException {
290 verifyAndRun(f, obj, Op.Set, new Action<Object>() {
291 @Override
292 public Object run(Field f, Object target) throws IllegalAccessException {
293 f.setDouble(target, value);
294 return null;
299 public static void setFloat(Field f, Object obj, final float value)
300 throws IllegalAccessException, IllegalArgumentException {
301 verifyAndRun(f, obj, Op.Set, new Action<Object>() {
302 @Override
303 public Object run(Field f, Object target) throws IllegalAccessException {
304 f.setFloat(target, value);
305 return null;
310 public static void setInt(Field f, Object obj, final int value)
311 throws IllegalAccessException, IllegalArgumentException {
312 verifyAndRun(f, obj, Op.Set, new Action<Object>() {
313 @Override
314 public Object run(Field f, Object target) throws IllegalAccessException {
315 f.setInt(target, value);
316 return null;
321 public static void setLong(Field f, Object obj, final long value)
322 throws IllegalAccessException, IllegalArgumentException {
323 verifyAndRun(f, obj, Op.Set, new Action<Object>() {
324 @Override
325 public Object run(Field f, Object target) throws IllegalAccessException {
326 f.setLong(target, value);
327 return null;
332 public static void setShort(Field f, Object obj, final short value)
333 throws IllegalAccessException, IllegalArgumentException {
334 verifyAndRun(f, obj, Op.Set, new Action<Object>() {
335 @Override
336 public Object run(Field f, Object target) throws IllegalAccessException {
337 f.setShort(target, value);
338 return null;
343 enum Op {
344 Get,
348 private interface Action<T> {
349 public T run(Field f, Object target) throws IllegalAccessException;
352 private static <T> T verifyAndRun(Field f, Object target, Op op, Action<T> action)
353 throws IllegalAccessException {
354 Class<?> userCaller = getCallerClassPrivileged(3);
355 if (op == Op.Get) {
356 verifyReadable(userCaller, f, target);
357 } else {
358 verifyWritable(userCaller, f, target);
361 AccessibilityModifier am = new AccessibilityModifier(f);
362 try {
363 return action.run(f, target);
364 } finally {
365 am.restore();
369 private static boolean isWhiteListed(Class<?> klass, Member member) {
370 if (klass == null) {
371 return false;
374 if (isWhiteListed_(klass, member)) {
375 return true;
378 if (member instanceof Constructor) {
379 return false;
382 Class<?>[] interfaces = klass.getInterfaces();
384 for (Class<?> i : interfaces) {
385 if (isWhiteListed(i, member)) {
386 return true;
390 Class<?> parentClass = klass.getSuperclass();
391 return isWhiteListed(parentClass, member);
394 private static boolean isWhiteListed_(Class<?> klass, Member member) {
395 if (isBlackListed(klass)) {
396 return false;
398 if (klass == member.getDeclaringClass()) {
399 return true;
401 return hasMember(klass, member);
404 private static boolean hasMember(Class<?> klass, Member member) {
405 if (member instanceof Method) {
406 Method m = (Method) member;
407 try {
408 klass.getDeclaredMethod(m.getName(), m.getParameterTypes());
409 return true;
410 } catch (NoSuchMethodException e) {
411 return false;
415 if (member instanceof Constructor) {
416 Constructor<?> constructor = (Constructor<?>) member;
417 try {
418 klass.getDeclaredConstructor(constructor.getParameterTypes());
419 return true;
420 } catch (NoSuchMethodException e) {
421 return false;
425 Field field = (Field) member;
426 try {
427 klass.getDeclaredField(field.getName());
428 return true;
429 } catch (NoSuchFieldException e) {
430 return false;
434 private static Class<?> getImmediateCallerClassPrivileged() {
435 return getCallerClassPrivileged(3);
438 private static Class<?> getCallerClassPrivileged(final int depth) {
439 return AccessController.doPrivileged(new PrivilegedAction<Class<?>>() {
440 @Override
441 public Class<?> run() {
442 return Reflection.getCallerClass(depth + 4);
447 private static <T extends AccessibleObject & Member> void checkAccess(final T m,
448 final Object target, Class<?> caller)
449 throws IllegalAccessException {
450 if (m.isAccessible()) {
451 return;
453 checkAccess(caller, m.getDeclaringClass(), target, m.getModifiers());
456 private static void checkAccess(final Class<?> caller, final Class<?> member, final Object target,
457 final int modifiers) throws IllegalAccessException {
458 try {
459 AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
460 @Override
461 public Object run() throws IllegalAccessException {
462 Reflection.ensureMemberAccess(caller, member, target, modifiers);
463 return null;
466 } catch (PrivilegedActionException e) {
467 Throwable t = e.getCause();
468 if (t instanceof IllegalAccessException) {
469 throw (IllegalAccessException) t;
471 throw new RuntimeException(t);
475 public static void throwAsUnchecked(Throwable t) {
476 Runtime.<RuntimeException>throwException_(t);
479 @SuppressWarnings("unchecked")
480 private static <T extends Throwable> void throwException_(Throwable t) throws T {
481 throw (T) t;
484 static class AccessibilityModifier {
485 private final AccessibleObject obj;
486 private final boolean originalAccessibility;
488 AccessibilityModifier(AccessibleObject obj) {
489 this.obj = obj;
490 originalAccessibility = obj.isAccessible();
491 setAccessible_(true);
494 public void restore() {
495 setAccessible_(originalAccessibility);
498 private void setAccessible_(final boolean flag) {
499 AccessController.doPrivileged(new PrivilegedAction<Object>() {
500 @Override
501 public Object run() {
502 obj.setAccessible(flag);
503 return null;