1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.portal.kernel.util;
21  
22  import com.liferay.portal.kernel.log.Log;
23  import com.liferay.portal.kernel.log.LogFactoryUtil;
24  
25  import java.io.ByteArrayInputStream;
26  import java.io.ByteArrayOutputStream;
27  import java.io.ObjectInputStream;
28  import java.io.ObjectOutputStream;
29  
30  import java.lang.Object;
31  import java.lang.reflect.InvocationTargetException;
32  import java.lang.reflect.Method;
33  
34  import java.util.ArrayList;
35  import java.util.List;
36  
37  /**
38   * <a href="ClassLoaderProxy.java.html"><b><i>View Source</i></b></a>
39   *
40   * @author Brian Wing Shun Chan
41   *
42   */
43  public class ClassLoaderProxy {
44  
45      public ClassLoaderProxy(Object obj, ClassLoader classLoader) {
46          _obj = obj;
47          _classLoader = classLoader;
48      }
49  
50      public ClassLoader getClassLoader() {
51          return _classLoader;
52      }
53  
54      public Object invoke(String methodName, Object[] args) throws Throwable {
55          Thread currentThread = Thread.currentThread();
56  
57          ClassLoader contextClassLoader = currentThread.getContextClassLoader();
58  
59          try {
60              currentThread.setContextClassLoader(_classLoader);
61  
62              Class<?> classObj = Class.forName(
63                  _obj.getClass().getName(), true, _classLoader);
64  
65              List<Class<?>> parameterTypes = new ArrayList<Class<?>>();
66  
67              for (int i = 0; i < args.length; i++) {
68                  Object arg = args[i];
69  
70                  Class<?> argClass = Class.forName(
71                      arg.getClass().getName(), true, _classLoader);
72  
73                  if (ClassUtil.isSubclass(argClass, PrimitiveWrapper.class)) {
74                      MethodKey methodKey = new MethodKey(
75                          argClass.getName(), "getValue", null);
76  
77                      Method method = MethodCache.get(methodKey);
78  
79                      args[i] = method.invoke(arg, (Object[])null);
80  
81                      argClass = (Class<?>)argClass.getField("TYPE").get(arg);
82                  }
83  
84                  if (ClassUtil.isSubclass(argClass, NullWrapper.class)) {
85                      NullWrapper nullWrapper = (NullWrapper)arg;
86  
87                      argClass = Class.forName(
88                          nullWrapper.getClassName(), true, _classLoader);
89  
90                      args[i] = null;
91                  }
92  
93                  parameterTypes.add(argClass);
94              }
95  
96              Method method = null;
97  
98              try {
99                  method = classObj.getMethod(
100                     methodName,
101                     parameterTypes.toArray(new Class[parameterTypes.size()]));
102             }
103             catch (NoSuchMethodException nsme) {
104                 Method[] methods = ((Class<?>)classObj).getMethods();
105 
106                 for (int i = 0; i < methods.length; i++) {
107                     Class<?>[] methodParameterTypes =
108                         methods[i].getParameterTypes();
109 
110                     if (methods[i].getName().equals(methodName) &&
111                         methodParameterTypes.length == parameterTypes.size()) {
112 
113                         boolean correctParams = true;
114 
115                         for (int j = 0; j < parameterTypes.size(); j++) {
116                             Class<?> a = parameterTypes.get(j);
117                             Class<?> b = methodParameterTypes[j];
118 
119                             if (!ClassUtil.isSubclass(a, b)) {
120                                 correctParams = false;
121 
122                                 break;
123                             }
124                         }
125 
126                         if (correctParams) {
127                             method = methods[i];
128 
129                             break;
130                         }
131                     }
132                 }
133 
134                 if (method == null) {
135                     throw nsme;
136                 }
137             }
138 
139             return method.invoke(_obj, args);
140         }
141         catch (InvocationTargetException ite) {
142             throw translateThrowable(ite.getCause(), contextClassLoader);
143         }
144         catch (Throwable t) {
145             _log.error(t, t);
146 
147             throw t;
148         }
149         finally {
150             currentThread.setContextClassLoader(contextClassLoader);
151         }
152     }
153 
154     protected Throwable translateThrowable(
155         Throwable t1, ClassLoader contextClassLoader) {
156 
157         try {
158             ByteArrayOutputStream baos = new ByteArrayOutputStream();
159             ObjectOutputStream oos = new ObjectOutputStream(baos);
160 
161             oos.writeObject(t1);
162 
163             oos.flush();
164             oos.close();
165 
166             byte[] bytes = baos.toByteArray();
167 
168             ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
169             ObjectInputStream ois = new ClassLoaderObjectInputStream(
170                 bais, contextClassLoader);
171 
172             t1 = (Throwable)ois.readObject();
173 
174             ois.close();
175 
176             return t1;
177         }
178         catch (Throwable t2) {
179             _log.error(t2, t2);
180 
181             return t2;
182         }
183     }
184 
185     private static Log _log = LogFactoryUtil.getLog(ClassLoaderProxy.class);
186 
187     private Object _obj;
188     private ClassLoader _classLoader;
189 
190 }