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

Save This Page
Home » openjdk-7 » sun » reflect » misc » [javadoc | source]