jaxws/src/java.xml.ws/share/classes/com/sun/xml/internal/ws/util/MethodUtil.java
changeset 43852 93a527059d8a
equal deleted inserted replaced
43752:3c68ef249093 43852:93a527059d8a
       
     1 /*
       
     2  * Copyright (c) 2017, 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 com.sun.xml.internal.ws.util;
       
    27 
       
    28 import java.io.IOException;
       
    29 import java.io.InputStream;
       
    30 import java.lang.reflect.InvocationTargetException;
       
    31 import java.lang.reflect.Method;
       
    32 import java.lang.reflect.Proxy;
       
    33 import java.security.AccessController;
       
    34 import java.security.AllPermission;
       
    35 import java.security.CodeSource;
       
    36 import java.security.PermissionCollection;
       
    37 import java.security.PrivilegedExceptionAction;
       
    38 import java.security.SecureClassLoader;
       
    39 import java.util.Arrays;
       
    40 
       
    41 /*
       
    42  * This copies from sun.reflect.misc.MethodUtil to implement the trampoline
       
    43  * code such that when a Method is invoked, it will be called through
       
    44  * the trampoline that is defined by this MethodUtil class loader.
       
    45  */
       
    46 class Trampoline {
       
    47     static {
       
    48         if (Trampoline.class.getClassLoader() == null) {
       
    49             throw new Error(
       
    50                     "Trampoline must not be defined by the bootstrap classloader");
       
    51         }
       
    52     }
       
    53 
       
    54     private static void ensureInvocableMethod(Method m)
       
    55             throws InvocationTargetException {
       
    56         Class<?> clazz = m.getDeclaringClass();
       
    57         if (clazz.equals(AccessController.class) ||
       
    58                 clazz.equals(Method.class) ||
       
    59                 clazz.getName().startsWith("java.lang.invoke."))
       
    60             throw new InvocationTargetException(
       
    61                     new UnsupportedOperationException("invocation not supported"));
       
    62     }
       
    63 
       
    64     private static Object invoke(Method m, Object obj, Object[] params)
       
    65             throws InvocationTargetException, IllegalAccessException {
       
    66         ensureInvocableMethod(m);
       
    67         return m.invoke(obj, params);
       
    68     }
       
    69 }
       
    70 
       
    71 /*
       
    72  * Create a trampoline class.
       
    73  */
       
    74 public final class MethodUtil extends SecureClassLoader {
       
    75     private static final String WS_UTIL_PKG = "com.sun.xml.internal.ws.util.";
       
    76     private static final String TRAMPOLINE = WS_UTIL_PKG + "Trampoline";
       
    77     private static final Method bounce = getTrampoline();
       
    78     private static final int DEFAULT_BUFFER_SIZE = 8192;
       
    79     private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
       
    80 
       
    81 
       
    82     private MethodUtil() {
       
    83         super();
       
    84     }
       
    85 
       
    86     /*
       
    87      * Bounce through the trampoline.
       
    88      */
       
    89     public static Object invoke(Method m, Object obj, Object[] params)
       
    90             throws InvocationTargetException, IllegalAccessException {
       
    91         try {
       
    92             return bounce.invoke(null, m, obj, params);
       
    93         } catch (InvocationTargetException ie) {
       
    94             Throwable t = ie.getCause();
       
    95 
       
    96             if (t instanceof InvocationTargetException) {
       
    97                 throw (InvocationTargetException) t;
       
    98             } else if (t instanceof IllegalAccessException) {
       
    99                 throw (IllegalAccessException) t;
       
   100             } else if (t instanceof RuntimeException) {
       
   101                 throw (RuntimeException) t;
       
   102             } else if (t instanceof Error) {
       
   103                 throw (Error) t;
       
   104             } else {
       
   105                 throw new Error("Unexpected invocation error", t);
       
   106             }
       
   107         } catch (IllegalAccessException iae) {
       
   108             // this can't happen
       
   109             throw new Error("Unexpected invocation error", iae);
       
   110         }
       
   111     }
       
   112 
       
   113     private static Method getTrampoline() {
       
   114         try {
       
   115             return AccessController.doPrivileged(
       
   116                     new PrivilegedExceptionAction<Method>() {
       
   117                         public Method run() throws Exception {
       
   118                             Class<?> t = getTrampolineClass();
       
   119                             Method b = t.getDeclaredMethod("invoke",
       
   120                                     Method.class, Object.class, Object[].class);
       
   121                             b.setAccessible(true);
       
   122                             return b;
       
   123                         }
       
   124                     });
       
   125         } catch (Exception e) {
       
   126             throw new InternalError("bouncer cannot be found", e);
       
   127         }
       
   128     }
       
   129 
       
   130 
       
   131     protected synchronized Class<?> loadClass(String name, boolean resolve)
       
   132             throws ClassNotFoundException {
       
   133         // First, check if the class has already been loaded
       
   134         checkPackageAccess(name);
       
   135         Class<?> c = findLoadedClass(name);
       
   136         if (c == null) {
       
   137             try {
       
   138                 c = findClass(name);
       
   139             } catch (ClassNotFoundException e) {
       
   140                 // Fall through ...
       
   141             }
       
   142             if (c == null) {
       
   143                 c = getParent().loadClass(name);
       
   144             }
       
   145         }
       
   146         if (resolve) {
       
   147             resolveClass(c);
       
   148         }
       
   149         return c;
       
   150     }
       
   151 
       
   152 
       
   153     protected Class<?> findClass(final String name)
       
   154             throws ClassNotFoundException {
       
   155         if (!name.startsWith(WS_UTIL_PKG)) {
       
   156             throw new ClassNotFoundException(name);
       
   157         }
       
   158         String path = "/".concat(name.replace('.', '/').concat(".class"));
       
   159         try (InputStream in = MethodUtil.class.getResourceAsStream(path)) {
       
   160             byte[] b = readAllBytes(in);
       
   161             return defineClass(name, b);
       
   162         } catch (IOException e) {
       
   163             throw new ClassNotFoundException(name, e);
       
   164         }
       
   165     }
       
   166 
       
   167     /**
       
   168      * JDK9 {@link InputStream#readAllBytes()} substitution.
       
   169      */
       
   170     private byte[] readAllBytes(InputStream in) throws IOException {
       
   171         byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
       
   172         int capacity = buf.length;
       
   173         int nread = 0;
       
   174         int n;
       
   175         for (; ; ) {
       
   176             // read to EOF which may read more or less than initial buffer size
       
   177             while ((n = in.read(buf, nread, capacity - nread)) > 0)
       
   178                 nread += n;
       
   179 
       
   180             // if the last call to read returned -1, then we're done
       
   181             if (n < 0)
       
   182                 break;
       
   183 
       
   184             // need to allocate a larger buffer
       
   185             if (capacity <= MAX_BUFFER_SIZE - capacity) {
       
   186                 capacity = capacity << 1;
       
   187             } else {
       
   188                 if (capacity == MAX_BUFFER_SIZE)
       
   189                     throw new OutOfMemoryError("Required array size too large");
       
   190                 capacity = MAX_BUFFER_SIZE;
       
   191             }
       
   192             buf = Arrays.copyOf(buf, capacity);
       
   193         }
       
   194         return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
       
   195     }
       
   196 
       
   197 
       
   198     /*
       
   199      * Define the proxy classes
       
   200      */
       
   201     private Class<?> defineClass(String name, byte[] b) throws IOException {
       
   202         CodeSource cs = new CodeSource(null, (java.security.cert.Certificate[]) null);
       
   203         if (!name.equals(TRAMPOLINE)) {
       
   204             throw new IOException("MethodUtil: bad name " + name);
       
   205         }
       
   206         return defineClass(name, b, 0, b.length, cs);
       
   207     }
       
   208 
       
   209     protected PermissionCollection getPermissions(CodeSource codesource) {
       
   210         PermissionCollection perms = super.getPermissions(codesource);
       
   211         perms.add(new AllPermission());
       
   212         return perms;
       
   213     }
       
   214 
       
   215     private static Class<?> getTrampolineClass() {
       
   216         try {
       
   217             return Class.forName(TRAMPOLINE, true, new MethodUtil());
       
   218         } catch (ClassNotFoundException e) {
       
   219         }
       
   220         return null;
       
   221     }
       
   222 
       
   223     /**
       
   224      * Checks package access on the given classname.
       
   225      * This method is typically called when the Class instance is not
       
   226      * available and the caller attempts to load a class on behalf
       
   227      * the true caller (application).
       
   228      */
       
   229     private static void checkPackageAccess(String name) {
       
   230         SecurityManager s = System.getSecurityManager();
       
   231         if (s != null) {
       
   232             String cname = name.replace('/', '.');
       
   233             if (cname.startsWith("[")) {
       
   234                 int b = cname.lastIndexOf('[') + 2;
       
   235                 if (b > 1 && b < cname.length()) {
       
   236                     cname = cname.substring(b);
       
   237                 }
       
   238             }
       
   239             int i = cname.lastIndexOf('.');
       
   240             if (i != -1) {
       
   241                 s.checkPackageAccess(cname.substring(0, i));
       
   242             }
       
   243         }
       
   244     }
       
   245 
       
   246     /**
       
   247      * Checks package access on the given class.
       
   248      * <p>
       
   249      * If it is a {@link Proxy#isProxyClass(Class)} that implements
       
   250      * a non-public interface (i.e. may be in a non-restricted package),
       
   251      * also check the package access on the proxy interfaces.
       
   252      */
       
   253     private static void checkPackageAccess(Class<?> clazz) {
       
   254         checkPackageAccess(clazz.getName());
       
   255         if (isNonPublicProxyClass(clazz)) {
       
   256             checkProxyPackageAccess(clazz);
       
   257         }
       
   258     }
       
   259 
       
   260     // Note that bytecode instrumentation tools may exclude 'sun.*'
       
   261     // classes but not generated proxy classes and so keep it in com.sun.*
       
   262     private static final String PROXY_PACKAGE = "com.sun.proxy";
       
   263 
       
   264     /**
       
   265      * Test if the given class is a proxy class that implements
       
   266      * non-public interface.  Such proxy class may be in a non-restricted
       
   267      * package that bypasses checkPackageAccess.
       
   268      */
       
   269     private static boolean isNonPublicProxyClass(Class<?> cls) {
       
   270         String name = cls.getName();
       
   271         int i = name.lastIndexOf('.');
       
   272         String pkg = (i != -1) ? name.substring(0, i) : "";
       
   273         return Proxy.isProxyClass(cls) && !pkg.startsWith(PROXY_PACKAGE);
       
   274     }
       
   275 
       
   276     /**
       
   277      * Check package access on the proxy interfaces that the given proxy class
       
   278      * implements.
       
   279      *
       
   280      * @param clazz Proxy class object
       
   281      */
       
   282     private static void checkProxyPackageAccess(Class<?> clazz) {
       
   283         SecurityManager s = System.getSecurityManager();
       
   284         if (s != null) {
       
   285             // check proxy interfaces if the given class is a proxy class
       
   286             if (Proxy.isProxyClass(clazz)) {
       
   287                 for (Class<?> intf : clazz.getInterfaces()) {
       
   288                     checkPackageAccess(intf);
       
   289                 }
       
   290             }
       
   291         }
       
   292     }
       
   293 }