| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| ContextClassLoaderProxy |
|
| 1.75;1.75 |
| 1 | /* | |
| 2 | * Copyright 2005-2007 The Kuali Foundation | |
| 3 | * | |
| 4 | * | |
| 5 | * Licensed under the Educational Community License, Version 2.0 (the "License"); | |
| 6 | * you may not use this file except in compliance with the License. | |
| 7 | * You may obtain a copy of the License at | |
| 8 | * | |
| 9 | * http://www.opensource.org/licenses/ecl2.php | |
| 10 | * | |
| 11 | * Unless required by applicable law or agreed to in writing, software | |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | * See the License for the specific language governing permissions and | |
| 15 | * limitations under the License. | |
| 16 | */ | |
| 17 | package org.kuali.rice.core.resourceloader; | |
| 18 | ||
| 19 | import java.lang.reflect.InvocationTargetException; | |
| 20 | import java.lang.reflect.Method; | |
| 21 | import java.lang.reflect.Proxy; | |
| 22 | ||
| 23 | import org.kuali.rice.core.proxy.BaseTargetedInvocationHandler; | |
| 24 | import org.kuali.rice.core.util.ClassLoaderUtils; | |
| 25 | ||
| 26 | /** | |
| 27 | * A Proxy that sets the thread Context ClassLoader before invocation of the | |
| 28 | * proxied object, and resets it back afterwards. | |
| 29 | * | |
| 30 | * @author Kuali Rice Team (rice.collab@kuali.org) | |
| 31 | */ | |
| 32 | public class ContextClassLoaderProxy extends BaseTargetedInvocationHandler { | |
| 33 | ||
| 34 | 0 | private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(ContextClassLoaderProxy.class); |
| 35 | ||
| 36 | /** | |
| 37 | * Convenience method that wraps a specified object with a ContextClassLoaderProxy, with a specified | |
| 38 | * handler classloader and proxy classloader. If the specified object is null, or the object classloader | |
| 39 | * equals the proxy classloader, the object is returned unwrapped. | |
| 40 | * @param proxiedObject the object to proxy | |
| 41 | * @param proxyClassLoader the classloader OF THE PROXY INSTANCE | |
| 42 | * @param objectClassLoader the classloader to set as the context classloader prior to any invocations on the proxiedObject | |
| 43 | * @return a ContextClassLoaderProxy Proxy for the proxiedObject | |
| 44 | */ | |
| 45 | public static Object wrap(Object proxiedObject, Class[] classesToProxy, ClassLoader proxyClassLoader, ClassLoader objectClassLoader) { | |
| 46 | 0 | if (proxiedObject == null) { |
| 47 | 0 | return null; |
| 48 | } | |
| 49 | 0 | if (proxyClassLoader == null) { |
| 50 | //proxyClassLoader = Thread.currentThread().getContextClassLoader(); | |
| 51 | 0 | proxyClassLoader = proxiedObject.getClass().getClassLoader(); |
| 52 | } | |
| 53 | 0 | if (objectClassLoader == null) { |
| 54 | 0 | objectClassLoader = proxiedObject.getClass().getClassLoader(); |
| 55 | } | |
| 56 | 0 | if (classesToProxy == null) { |
| 57 | 0 | classesToProxy = getInterfacesToProxy(proxyClassLoader, proxiedObject); |
| 58 | } | |
| 59 | // this classloader comparison looks fishy | |
| 60 | // it is testing the classloader of the proxy against the intended *context* classloader of the proxiedObject | |
| 61 | // if these are the same the proxiedObject is not wrapped. However, that implies that if the proxy | |
| 62 | // classloader may equal the intended context class loader, that the context class loader is actually not set, | |
| 63 | // and could theoretically NOT be the intended one in the future | |
| 64 | // somebody who understands this better than me should investigate this, and this method which I have | |
| 65 | // now applied to all prior uses of ContextClassLoaderProxy as a convenience | |
| 66 | //if (proxiedObject != null) { //&& !objectClassLoader.equals(proxyClassLoader)) { | |
| 67 | 0 | ContextClassLoaderProxy handler = new ContextClassLoaderProxy(objectClassLoader, proxiedObject); |
| 68 | 0 | LOG.debug("Installed a ContextClassLoaderProxy on object: " + proxiedObject.getClass().getName()); |
| 69 | 0 | proxiedObject = Proxy.newProxyInstance(proxyClassLoader, classesToProxy, handler); |
| 70 | //} | |
| 71 | ||
| 72 | 0 | return proxiedObject; |
| 73 | } | |
| 74 | ||
| 75 | public static Object wrap(Object proxiedObject, ClassLoader proxyClassLoader, ClassLoader objectClassLoader) { | |
| 76 | 0 | return wrap(proxiedObject, null, proxyClassLoader, objectClassLoader); |
| 77 | } | |
| 78 | ||
| 79 | public static Object wrap(Object proxiedObject, ClassLoader classLoader) { | |
| 80 | 0 | return wrap(proxiedObject, classLoader, classLoader); |
| 81 | } | |
| 82 | ||
| 83 | public static Object wrap(Object proxiedObject, Class[] classesToProxy) { | |
| 84 | 0 | return wrap(proxiedObject, classesToProxy, null, null); |
| 85 | } | |
| 86 | ||
| 87 | public static Object wrap(Object proxiedObject, Class[] classesToProxy, ClassLoader classLoader) { | |
| 88 | 0 | return wrap(proxiedObject, classesToProxy, classLoader, classLoader); |
| 89 | } | |
| 90 | ||
| 91 | public static Object wrap(Object proxiedObject) { | |
| 92 | 0 | return wrap(proxiedObject, null, null, null); |
| 93 | } | |
| 94 | ||
| 95 | ||
| 96 | // public static Class[] getInterfacesToProxy(Object proxiedObject) { | |
| 97 | // List interfaces = ClassUtils.getAllInterfaces(proxiedObject.getClass()); | |
| 98 | // for (Iterator iterator = interfaces.iterator(); iterator.hasNext();) { | |
| 99 | // Class objectInterface = (Class) iterator.next(); | |
| 100 | // if (objectInterface.getName().startsWith("org.springframework")) { | |
| 101 | // iterator.remove(); | |
| 102 | // } | |
| 103 | // } | |
| 104 | // Class[] interfaceArray = new Class[interfaces.size()]; | |
| 105 | // return (Class[]) interfaces.toArray(interfaceArray); | |
| 106 | // } | |
| 107 | ||
| 108 | public static Class[] getInterfacesToProxyIncludeSpring(Object proxiedObject) { | |
| 109 | 0 | return getInterfacesToProxyIncludeSpring(null, proxiedObject); |
| 110 | } | |
| 111 | ||
| 112 | /** | |
| 113 | * @deprecated use getInterfacesToProxy instead. Removed the filtering of Spring because it is no longer | |
| 114 | * needed since the embedded plugin went away (we may have to revisit this at some point in the future). | |
| 115 | */ | |
| 116 | public static Class[] getInterfacesToProxyIncludeSpring(ClassLoader proxyClassLoader, Object proxiedObject) { | |
| 117 | 0 | return getInterfacesToProxy(proxyClassLoader, proxiedObject); |
| 118 | } | |
| 119 | ||
| 120 | public static Class[] getInterfacesToProxy(Object proxiedObject) { | |
| 121 | 0 | return getInterfacesToProxy(null, proxiedObject); |
| 122 | } | |
| 123 | ||
| 124 | /** | |
| 125 | * Determines the interfaces which need to be proxied and are visable to the given proxy ClassLoader. | |
| 126 | */ | |
| 127 | public static Class[] getInterfacesToProxy(ClassLoader proxyClassLoader, Object proxiedObject) { | |
| 128 | 0 | return ClassLoaderUtils.getInterfacesToProxy(proxiedObject, proxyClassLoader, null); |
| 129 | } | |
| 130 | ||
| 131 | private ClassLoader classLoader; | |
| 132 | ||
| 133 | public ContextClassLoaderProxy(ClassLoader classLoader, Object target) { | |
| 134 | 0 | super(target); |
| 135 | 0 | this.classLoader = classLoader; |
| 136 | 0 | } |
| 137 | ||
| 138 | protected Object invokeInternal(Object proxy, Method m, Object[] args) throws Throwable { | |
| 139 | 0 | ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); |
| 140 | try { | |
| 141 | 0 | Thread.currentThread().setContextClassLoader(this.classLoader); |
| 142 | 0 | return m.invoke(getTarget(), args); |
| 143 | 0 | } catch (InvocationTargetException e) { |
| 144 | 0 | throw (e.getCause() != null ? e.getCause() : e); |
| 145 | } finally { | |
| 146 | 0 | Thread.currentThread().setContextClassLoader(oldCl); |
| 147 | } | |
| 148 | } | |
| 149 | } |