1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/reflect/opt/Injector.java Wed Apr 27 01:27:09 2016 +0800 1.3 @@ -0,0 +1,305 @@ 1.4 +/* 1.5 + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Oracle designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Oracle in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.25 + * or visit www.oracle.com if you need additional information or have any 1.26 + * questions. 1.27 + */ 1.28 + 1.29 +package com.sun.xml.internal.bind.v2.runtime.reflect.opt; 1.30 + 1.31 +import java.lang.reflect.InvocationTargetException; 1.32 +import java.lang.reflect.Method; 1.33 +import java.lang.ref.WeakReference; 1.34 +import java.security.AccessController; 1.35 +import java.security.PrivilegedAction; 1.36 +import java.util.concurrent.locks.Lock; 1.37 +import java.util.concurrent.locks.ReentrantReadWriteLock; 1.38 +import java.util.HashMap; 1.39 +import java.util.Map; 1.40 +import java.util.WeakHashMap; 1.41 +import java.util.logging.Level; 1.42 +import java.util.logging.Logger; 1.43 + 1.44 +import com.sun.xml.internal.bind.Util; 1.45 +import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; 1.46 + 1.47 +/** 1.48 + * A {@link ClassLoader} used to "inject" optimized accessor classes 1.49 + * into the VM. 1.50 + * 1.51 + * <p> 1.52 + * Its parent class loader needs to be set to the one that can see the user 1.53 + * class. 1.54 + * 1.55 + * @author Kohsuke Kawaguchi 1.56 + */ 1.57 +final class Injector { 1.58 + 1.59 + /** 1.60 + * {@link Injector}s keyed by their parent {@link ClassLoader}. 1.61 + * 1.62 + * We only need one injector per one user class loader. 1.63 + */ 1.64 + private static final ReentrantReadWriteLock irwl = new ReentrantReadWriteLock(); 1.65 + private static final Lock ir = irwl.readLock(); 1.66 + private static final Lock iw = irwl.writeLock(); 1.67 + private static final Map<ClassLoader, WeakReference<Injector>> injectors = 1.68 + new WeakHashMap<ClassLoader, WeakReference<Injector>>(); 1.69 + private static final Logger logger = Util.getClassLogger(); 1.70 + 1.71 + /** 1.72 + * Injects a new class into the given class loader. 1.73 + * 1.74 + * @return null 1.75 + * if it fails to inject. 1.76 + */ 1.77 + static Class inject(ClassLoader cl, String className, byte[] image) { 1.78 + Injector injector = get(cl); 1.79 + if (injector != null) { 1.80 + return injector.inject(className, image); 1.81 + } else { 1.82 + return null; 1.83 + } 1.84 + } 1.85 + 1.86 + /** 1.87 + * Returns the already injected class, or null. 1.88 + */ 1.89 + static Class find(ClassLoader cl, String className) { 1.90 + Injector injector = get(cl); 1.91 + if (injector != null) { 1.92 + return injector.find(className); 1.93 + } else { 1.94 + return null; 1.95 + } 1.96 + } 1.97 + 1.98 + /** 1.99 + * Gets or creates an {@link Injector} for the given class loader. 1.100 + * 1.101 + * @return null 1.102 + * if it fails. 1.103 + */ 1.104 + private static Injector get(ClassLoader cl) { 1.105 + Injector injector = null; 1.106 + WeakReference<Injector> wr; 1.107 + ir.lock(); 1.108 + try { 1.109 + wr = injectors.get(cl); 1.110 + } finally { 1.111 + ir.unlock(); 1.112 + } 1.113 + if (wr != null) { 1.114 + injector = wr.get(); 1.115 + } 1.116 + if (injector == null) { 1.117 + try { 1.118 + wr = new WeakReference<Injector>(injector = new Injector(cl)); 1.119 + iw.lock(); 1.120 + try { 1.121 + if (!injectors.containsKey(cl)) { 1.122 + injectors.put(cl, wr); 1.123 + } 1.124 + } finally { 1.125 + iw.unlock(); 1.126 + } 1.127 + } catch (SecurityException e) { 1.128 + logger.log(Level.FINE, "Unable to set up a back-door for the injector", e); 1.129 + return null; 1.130 + } 1.131 + } 1.132 + return injector; 1.133 + } 1.134 + /** 1.135 + * Injected classes keyed by their names. 1.136 + */ 1.137 + private final Map<String, Class> classes = new HashMap<String, Class>(); 1.138 + private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); 1.139 + private final Lock r = rwl.readLock(); 1.140 + private final Lock w = rwl.writeLock(); 1.141 + private final ClassLoader parent; 1.142 + /** 1.143 + * True if this injector is capable of injecting accessors. 1.144 + * False otherwise, which happens if this classloader can't see {@link Accessor}. 1.145 + */ 1.146 + private final boolean loadable; 1.147 + private static final Method defineClass; 1.148 + private static final Method resolveClass; 1.149 + private static final Method findLoadedClass; 1.150 + 1.151 + static { 1.152 + try { 1.153 + defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, Integer.TYPE, Integer.TYPE); 1.154 + resolveClass = ClassLoader.class.getDeclaredMethod("resolveClass", Class.class); 1.155 + findLoadedClass = ClassLoader.class.getDeclaredMethod("findLoadedClass", String.class); 1.156 + } catch (NoSuchMethodException e) { 1.157 + // impossible 1.158 + throw new NoSuchMethodError(e.getMessage()); 1.159 + } 1.160 + AccessController.doPrivileged(new PrivilegedAction<Void>() { 1.161 + 1.162 + @Override 1.163 + public Void run() { 1.164 + // TODO: check security implication 1.165 + // do these setAccessible allow anyone to call these methods freely?s 1.166 + defineClass.setAccessible(true); 1.167 + resolveClass.setAccessible(true); 1.168 + findLoadedClass.setAccessible(true); 1.169 + return null; 1.170 + } 1.171 + }); 1.172 + } 1.173 + 1.174 + private Injector(ClassLoader parent) { 1.175 + this.parent = parent; 1.176 + assert parent != null; 1.177 + 1.178 + boolean loadableCheck = false; 1.179 + 1.180 + try { 1.181 + loadableCheck = parent.loadClass(Accessor.class.getName()) == Accessor.class; 1.182 + } catch (ClassNotFoundException e) { 1.183 + // not loadable 1.184 + } 1.185 + 1.186 + this.loadable = loadableCheck; 1.187 + } 1.188 + 1.189 + @SuppressWarnings("LockAcquiredButNotSafelyReleased") 1.190 + private Class inject(String className, byte[] image) { 1.191 + if (!loadable) // this injector cannot inject anything 1.192 + { 1.193 + return null; 1.194 + } 1.195 + 1.196 + boolean wlocked = false; 1.197 + boolean rlocked = false; 1.198 + try { 1.199 + 1.200 + r.lock(); 1.201 + rlocked = true; 1.202 + 1.203 + Class c = classes.get(className); 1.204 + 1.205 + // Unlock now during the findLoadedClass process to avoid 1.206 + // deadlocks 1.207 + r.unlock(); 1.208 + rlocked = false; 1.209 + 1.210 + //find loaded class from classloader 1.211 + if (c == null) { 1.212 + 1.213 + try { 1.214 + c = (Class) findLoadedClass.invoke(parent, className.replace('/', '.')); 1.215 + } catch (IllegalArgumentException e) { 1.216 + logger.log(Level.FINE, "Unable to find " + className, e); 1.217 + } catch (IllegalAccessException e) { 1.218 + logger.log(Level.FINE, "Unable to find " + className, e); 1.219 + } catch (InvocationTargetException e) { 1.220 + Throwable t = e.getTargetException(); 1.221 + logger.log(Level.FINE, "Unable to find " + className, t); 1.222 + } 1.223 + 1.224 + if (c != null) { 1.225 + 1.226 + w.lock(); 1.227 + wlocked = true; 1.228 + 1.229 + classes.put(className, c); 1.230 + 1.231 + w.unlock(); 1.232 + wlocked = false; 1.233 + 1.234 + return c; 1.235 + } 1.236 + } 1.237 + 1.238 + if (c == null) { 1.239 + 1.240 + r.lock(); 1.241 + rlocked = true; 1.242 + 1.243 + c = classes.get(className); 1.244 + 1.245 + // Unlock now during the define/resolve process to avoid 1.246 + // deadlocks 1.247 + r.unlock(); 1.248 + rlocked = false; 1.249 + 1.250 + if (c == null) { 1.251 + 1.252 + // we need to inject a class into the 1.253 + try { 1.254 + c = (Class) defineClass.invoke(parent, className.replace('/', '.'), image, 0, image.length); 1.255 + resolveClass.invoke(parent, c); 1.256 + } catch (IllegalAccessException e) { 1.257 + logger.log(Level.FINE, "Unable to inject " + className, e); 1.258 + return null; 1.259 + } catch (InvocationTargetException e) { 1.260 + Throwable t = e.getTargetException(); 1.261 + if (t instanceof LinkageError) { 1.262 + logger.log(Level.FINE, "duplicate class definition bug occured? Please report this : " + className, t); 1.263 + } else { 1.264 + logger.log(Level.FINE, "Unable to inject " + className, t); 1.265 + } 1.266 + return null; 1.267 + } catch (SecurityException e) { 1.268 + logger.log(Level.FINE, "Unable to inject " + className, e); 1.269 + return null; 1.270 + } catch (LinkageError e) { 1.271 + logger.log(Level.FINE, "Unable to inject " + className, e); 1.272 + return null; 1.273 + } 1.274 + 1.275 + w.lock(); 1.276 + wlocked = true; 1.277 + 1.278 + // During the time we were unlocked, we could have tried to 1.279 + // load the class from more than one thread. Check now to see 1.280 + // if someone else beat us to registering this class 1.281 + if (!classes.containsKey(className)) { 1.282 + classes.put(className, c); 1.283 + } 1.284 + 1.285 + w.unlock(); 1.286 + wlocked = false; 1.287 + } 1.288 + } 1.289 + return c; 1.290 + } finally { 1.291 + if (rlocked) { 1.292 + r.unlock(); 1.293 + } 1.294 + if (wlocked) { 1.295 + w.unlock(); 1.296 + } 1.297 + } 1.298 + } 1.299 + 1.300 + private Class find(String className) { 1.301 + r.lock(); 1.302 + try { 1.303 + return classes.get(className); 1.304 + } finally { 1.305 + r.unlock(); 1.306 + } 1.307 + } 1.308 +}