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