1 /* 2 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.reflect.misc; 27 28 import java.security.AllPermission; 29 import java.security.AccessController; 30 import java.security.PermissionCollection; 31 import java.security.SecureClassLoader; 32 import java.security.PrivilegedExceptionAction; 33 import java.security.CodeSource; 34 import java.io.InputStream; 35 import java.io.BufferedInputStream; 36 import java.io.IOException; 37 import java.net.URL; 38 import java.net.URLConnection; 39 import java.lang.reflect.Method; 40 import java.lang.reflect.InvocationTargetException; 41 import java.lang.reflect.AccessibleObject; 42 import java.lang.reflect.Modifier; 43 import java.util.Arrays; 44 import java.util.HashMap; 45 import java.util.Map; 46 import sun.misc.IOUtils; 47 48 49 class Trampoline { 50 static { 51 if (Trampoline.class.getClassLoader() == null) { 52 throw new Error( 53 "Trampoline must not be defined by the bootstrap classloader"); 54 } 55 } 56 57 private static void ensureInvocableMethod(Method m) 58 throws InvocationTargetException 59 { 60 Class<?> clazz = m.getDeclaringClass(); 61 if (clazz.equals(AccessController.class) || 62 clazz.equals(Method.class) || 63 clazz.getName().startsWith("java.lang.invoke.")) 64 throw new InvocationTargetException( 65 new UnsupportedOperationException("invocation not supported")); 66 } 67 68 private static Object invoke(Method m, Object obj, Object[] params) 69 throws InvocationTargetException, IllegalAccessException 70 { 71 ensureInvocableMethod(m); 72 return m.invoke(obj, params); 73 } 74 } 75 76 /* 77 * Create a trampoline class. 78 */ 79 public final class MethodUtil extends SecureClassLoader { 80 private static final String MISC_PKG = "sun.reflect.misc."; 81 private static final String TRAMPOLINE = MISC_PKG + "Trampoline"; 82 private static final Method bounce = getTrampoline(); 83 84 private MethodUtil() { 85 super(); 86 } 87 88 public static Method getMethod(Class<?> cls, String name, Class<?>[] args) 89 throws NoSuchMethodException { 90 ReflectUtil.checkPackageAccess(cls); 91 return cls.getMethod(name, args); 92 } 93 94 public static Method[] getMethods(Class<?> cls) { 95 ReflectUtil.checkPackageAccess(cls); 96 return cls.getMethods(); 97 } 98 99 /* 100 * Discover the public methods on public classes 101 * and interfaces accessible to any caller by calling 102 * Class.getMethods() and walking towards Object until 103 * we're done. 104 */ 105 public static Method[] getPublicMethods(Class<?> cls) { 106 // compatibility for update release 107 if (System.getSecurityManager() == null) { 108 return cls.getMethods(); 109 } 110 Map<Signature, Method> sigs = new HashMap<Signature, Method>(); 111 while (cls != null) { 112 boolean done = getInternalPublicMethods(cls, sigs); 113 if (done) { 114 break; 115 } 116 getInterfaceMethods(cls, sigs); 117 cls = cls.getSuperclass(); 118 } 119 return sigs.values().toArray(new Method[sigs.size()]); 120 } 121 122 /* 123 * Process the immediate interfaces of this class or interface. 124 */ 125 private static void getInterfaceMethods(Class<?> cls, 126 Map<Signature, Method> sigs) { 127 Class<?>[] intfs = cls.getInterfaces(); 128 for (int i=0; i < intfs.length; i++) { 129 Class<?> intf = intfs[i]; 130 boolean done = getInternalPublicMethods(intf, sigs); 131 if (!done) { 132 getInterfaceMethods(intf, sigs); 133 } 134 } 135 } 136 137 /* 138 * 139 * Process the methods in this class or interface 140 */ 141 private static boolean getInternalPublicMethods(Class<?> cls, 142 Map<Signature, Method> sigs) { 143 Method[] methods = null; 144 try { 145 /* 146 * This class or interface is non-public so we 147 * can't use any of it's methods. Go back and 148 * try again with a superclass or superinterface. 149 */ 150 if (!Modifier.isPublic(cls.getModifiers())) { 151 return false; 152 } 153 if (!ReflectUtil.isPackageAccessible(cls)) { 154 return false; 155 } 156 157 methods = cls.getMethods(); 158 } catch (SecurityException se) { 159 return false; 160 } 161 162 /* 163 * Check for inherited methods with non-public 164 * declaring classes. They might override and hide 165 * methods from their superclasses or 166 * superinterfaces. 167 */ 168 boolean done = true; 169 for (int i=0; i < methods.length; i++) { 170 Class<?> dc = methods[i].getDeclaringClass(); 171 if (!Modifier.isPublic(dc.getModifiers())) { 172 done = false; 173 break; 174 } 175 } 176 177 if (done) { 178 /* 179 * We're done. Spray all the methods into 180 * the list and then we're out of here. 181 */ 182 for (int i=0; i < methods.length; i++) { 183 addMethod(sigs, methods[i]); 184 } 185 } else { 186 /* 187 * Simulate cls.getDeclaredMethods() by 188 * stripping away inherited methods. 189 */ 190 for (int i=0; i < methods.length; i++) { 191 Class<?> dc = methods[i].getDeclaringClass(); 192 if (cls.equals(dc)) { 193 addMethod(sigs, methods[i]); 194 } 195 } 196 } 197 return done; 198 } 199 200 private static void addMethod(Map<Signature, Method> sigs, Method method) { 201 Signature signature = new Signature(method); 202 if (!sigs.containsKey(signature)) { 203 sigs.put(signature, method); 204 } else if (!method.getDeclaringClass().isInterface()){ 205 /* 206 * Superclasses beat interfaces. 207 */ 208 Method old = sigs.get(signature); 209 if (old.getDeclaringClass().isInterface()) { 210 sigs.put(signature, method); 211 } 212 } 213 } 214 215 /** 216 * A class that represents the unique elements of a method that will be a 217 * key in the method cache. 218 */ 219 private static class Signature { 220 private final String methodName; 221 private final Class<?>[] argClasses; 222 private final int hashCode; 223 224 Signature(Method m) { 225 this.methodName = m.getName(); 226 this.argClasses = m.getParameterTypes(); 227 this.hashCode = methodName.hashCode() + Arrays.hashCode(argClasses); 228 } 229 230 @Override public int hashCode() { 231 return hashCode; 232 } 233 234 @Override public boolean equals(Object o2) { 235 if (this == o2) { 236 return true; 237 } 238 Signature that = (Signature)o2; 239 if (!(methodName.equals(that.methodName))) { 240 return false; 241 } 242 if (argClasses.length != that.argClasses.length) { 243 return false; 244 } 245 for (int i = 0; i < argClasses.length; i++) { 246 if (!(argClasses[i] == that.argClasses[i])) { 247 return false; 248 } 249 } 250 return true; 251 } 252 } 253 254 255 /* 256 * Bounce through the trampoline. 257 */ 258 public static Object invoke(Method m, Object obj, Object[] params) 259 throws InvocationTargetException, IllegalAccessException { 260 try { 261 return bounce.invoke(null, new Object[] {m, obj, params}); 262 } catch (InvocationTargetException ie) { 263 Throwable t = ie.getCause(); 264 265 if (t instanceof InvocationTargetException) { 266 throw (InvocationTargetException)t; 267 } else if (t instanceof IllegalAccessException) { 268 throw (IllegalAccessException)t; 269 } else if (t instanceof RuntimeException) { 270 throw (RuntimeException)t; 271 } else if (t instanceof Error) { 272 throw (Error)t; 273 } else { 274 throw new Error("Unexpected invocation error", t); 275 } 276 } catch (IllegalAccessException iae) { 277 // this can't happen 278 throw new Error("Unexpected invocation error", iae); 279 } 280 } 281 282 private static Method getTrampoline() { 283 try { 284 return AccessController.doPrivileged( 285 new PrivilegedExceptionAction<Method>() { 286 public Method run() throws Exception { 287 Class<?> t = getTrampolineClass(); 288 Class<?>[] types = { 289 Method.class, Object.class, Object[].class 290 }; 291 Method b = t.getDeclaredMethod("invoke", types); 292 b.setAccessible(true); 293 return b; 294 } 295 }); 296 } catch (Exception e) { 297 throw new InternalError("bouncer cannot be found", e); 298 } 299 } 300 301 302 protected synchronized Class<?> loadClass(String name, boolean resolve) 303 throws ClassNotFoundException 304 { 305 // First, check if the class has already been loaded 306 ReflectUtil.checkPackageAccess(name); 307 Class<?> c = findLoadedClass(name); 308 if (c == null) { 309 try { 310 c = findClass(name); 311 } catch (ClassNotFoundException e) { 312 // Fall through ... 313 } 314 if (c == null) { 315 c = getParent().loadClass(name); 316 } 317 } 318 if (resolve) { 319 resolveClass(c); 320 } 321 return c; 322 } 323 324 325 protected Class<?> findClass(final String name) 326 throws ClassNotFoundException 327 { 328 if (!name.startsWith(MISC_PKG)) { 329 throw new ClassNotFoundException(name); 330 } 331 String path = name.replace('.', '/').concat(".class"); 332 URL res = getResource(path); 333 if (res != null) { 334 try { 335 return defineClass(name, res); 336 } catch (IOException e) { 337 throw new ClassNotFoundException(name, e); 338 } 339 } else { 340 throw new ClassNotFoundException(name); 341 } 342 } 343 344 345 /* 346 * Define the proxy classes 347 */ 348 private Class<?> defineClass(String name, URL url) throws IOException { 349 byte[] b = getBytes(url); 350 CodeSource cs = new CodeSource(null, (java.security.cert.Certificate[])null); 351 if (!name.equals(TRAMPOLINE)) { 352 throw new IOException("MethodUtil: bad name " + name); 353 } 354 return defineClass(name, b, 0, b.length, cs); 355 } 356 357 358 /* 359 * Returns the contents of the specified URL as an array of bytes. 360 */ 361 private static byte[] getBytes(URL url) throws IOException { 362 URLConnection uc = url.openConnection(); 363 if (uc instanceof java.net.HttpURLConnection) { 364 java.net.HttpURLConnection huc = (java.net.HttpURLConnection) uc; 365 int code = huc.getResponseCode(); 366 if (code >= java.net.HttpURLConnection.HTTP_BAD_REQUEST) { 367 throw new IOException("open HTTP connection failed."); 368 } 369 } 370 int len = uc.getContentLength(); 371 InputStream in = new BufferedInputStream(uc.getInputStream()); 372 373 byte[] b; 374 try { 375 b = IOUtils.readFully(in, len, true); 376 } finally { 377 in.close(); 378 } 379 return b; 380 } 381 382 383 protected PermissionCollection getPermissions(CodeSource codesource) 384 { 385 PermissionCollection perms = super.getPermissions(codesource); 386 perms.add(new AllPermission()); 387 return perms; 388 } 389 390 private static Class<?> getTrampolineClass() { 391 try { 392 return Class.forName(TRAMPOLINE, true, new MethodUtil()); 393 } catch (ClassNotFoundException e) { 394 } 395 return null; 396 } 397 398 }