001: /*
002: * Copyright 2005-2006 The Kuali Foundation.
003: *
004: *
005: * Licensed under the Educational Community License, Version 1.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.opensource.org/licenses/ecl1.php
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.kuali.rice.resourceloader;
018:
019: import java.lang.reflect.InvocationTargetException;
020: import java.lang.reflect.Method;
021: import java.lang.reflect.Proxy;
022: import java.util.Iterator;
023: import java.util.List;
024:
025: import org.apache.commons.lang.ClassUtils;
026: import org.kuali.rice.proxy.BaseTargetedInvocationHandler;
027: import org.kuali.rice.util.ClassLoaderUtils;
028:
029: /**
030: * A Proxy that sets the thread Context ClassLoader before invocation of the
031: * proxied object, and resets it back afterwards.
032: *
033: * @author Kuali Rice Team (kuali-rice@googlegroups.com)
034: */
035: public class ContextClassLoaderProxy extends
036: BaseTargetedInvocationHandler {
037:
038: private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger
039: .getLogger(ContextClassLoaderProxy.class);
040:
041: /**
042: * Convenience method that wraps a specified object with a ContextClassLoaderProxy, with a specified
043: * handler classloader and proxy classloader. If the specified object is null, or the object classloader
044: * equals the proxy classloader, the object is returned unwrapped.
045: * @param proxiedObject the object to proxy
046: * @param proxyClassLoader the classloader OF THE PROXY INSTANCE
047: * @param objectClassLoader the classloader to set as the context classloader prior to any invocations on the proxiedObject
048: * @return a ContextClassLoaderProxy Proxy for the proxiedObject
049: */
050: public static Object wrap(Object proxiedObject,
051: Class[] classesToProxy, ClassLoader proxyClassLoader,
052: ClassLoader objectClassLoader) {
053: if (proxiedObject == null) {
054: return null;
055: }
056: if (proxyClassLoader == null) {
057: //proxyClassLoader = Thread.currentThread().getContextClassLoader();
058: proxyClassLoader = proxiedObject.getClass()
059: .getClassLoader();
060: }
061: if (objectClassLoader == null) {
062: objectClassLoader = proxiedObject.getClass()
063: .getClassLoader();
064: }
065: if (classesToProxy == null) {
066: classesToProxy = getInterfacesToProxy(proxyClassLoader,
067: proxiedObject);
068: }
069: // this classloader comparison looks fishy
070: // it is testing the classloader of the proxy against the intended *context* classloader of the proxiedObject
071: // if these are the same the proxiedObject is not wrapped. However, that implies that if the proxy
072: // classloader may equal the intended context class loader, that the context class loader is actually not set,
073: // and could theoretically NOT be the intended one in the future
074: // somebody who understands this better than me should investigate this, and this method which I have
075: // now applied to all prior uses of ContextClassLoaderProxy as a convenience
076: //if (proxiedObject != null) { //&& !objectClassLoader.equals(proxyClassLoader)) {
077: ContextClassLoaderProxy handler = new ContextClassLoaderProxy(
078: objectClassLoader, proxiedObject);
079: proxiedObject = Proxy.newProxyInstance(proxyClassLoader,
080: classesToProxy, handler);
081: //}
082: return proxiedObject;
083: }
084:
085: public static Object wrap(Object proxiedObject,
086: ClassLoader proxyClassLoader, ClassLoader objectClassLoader) {
087: return wrap(proxiedObject, null, proxyClassLoader,
088: objectClassLoader);
089: }
090:
091: public static Object wrap(Object proxiedObject,
092: ClassLoader classLoader) {
093: return wrap(proxiedObject, classLoader, classLoader);
094: }
095:
096: public static Object wrap(Object proxiedObject,
097: Class[] classesToProxy) {
098: return wrap(proxiedObject, classesToProxy, null, null);
099: }
100:
101: public static Object wrap(Object proxiedObject,
102: Class[] classesToProxy, ClassLoader classLoader) {
103: return wrap(proxiedObject, classesToProxy, classLoader,
104: classLoader);
105: }
106:
107: public static Object wrap(Object proxiedObject) {
108: return wrap(proxiedObject, null, null, null);
109: }
110:
111: // public static Class[] getInterfacesToProxy(Object proxiedObject) {
112: // List interfaces = ClassUtils.getAllInterfaces(proxiedObject.getClass());
113: // for (Iterator iterator = interfaces.iterator(); iterator.hasNext();) {
114: // Class objectInterface = (Class) iterator.next();
115: // if (objectInterface.getName().startsWith("org.springframework")) {
116: // iterator.remove();
117: // }
118: // }
119: // Class[] interfaceArray = new Class[interfaces.size()];
120: // return (Class[]) interfaces.toArray(interfaceArray);
121: // }
122:
123: public static Class[] getInterfacesToProxyIncludeSpring(
124: Object proxiedObject) {
125: return getInterfacesToProxyIncludeSpring(null, proxiedObject);
126: }
127:
128: /**
129: * @deprecated use getInterfacesToProxy instead. Removed the filtering of Spring because it is no longer
130: * needed since the embedded plugin went away (we may have to revisit this at some point in the future).
131: */
132: public static Class[] getInterfacesToProxyIncludeSpring(
133: ClassLoader proxyClassLoader, Object proxiedObject) {
134: return getInterfacesToProxy(proxyClassLoader, proxiedObject);
135: }
136:
137: public static Class[] getInterfacesToProxy(Object proxiedObject) {
138: return getInterfacesToProxy(null, proxiedObject);
139: }
140:
141: /**
142: * Determines the interfaces which need to be proxied and are visable to the given proxy ClassLoader.
143: */
144: public static Class[] getInterfacesToProxy(
145: ClassLoader proxyClassLoader, Object proxiedObject) {
146: return ClassLoaderUtils.getInterfacesToProxy(proxiedObject,
147: proxyClassLoader, null);
148: }
149:
150: private ClassLoader classLoader;
151:
152: public ContextClassLoaderProxy(ClassLoader classLoader,
153: Object target) {
154: super (target);
155: this .classLoader = classLoader;
156: }
157:
158: protected Object invokeInternal(Object proxy, Method m,
159: Object[] args) throws Throwable {
160: ClassLoader oldCl = Thread.currentThread()
161: .getContextClassLoader();
162: try {
163: Thread.currentThread().setContextClassLoader(
164: this .classLoader);
165: return m.invoke(getTarget(), args);
166: } catch (InvocationTargetException e) {
167: throw (e.getCause() != null ? e.getCause() : e);
168: } finally {
169: Thread.currentThread().setContextClassLoader(oldCl);
170: }
171: }
172: }
|