1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.kernel.util;
24  
25  import com.liferay.portal.kernel.log.Log;
26  import com.liferay.portal.kernel.log.LogFactoryUtil;
27  
28  import java.lang.reflect.Array;
29  import java.lang.reflect.InvocationTargetException;
30  import java.lang.reflect.Method;
31  
32  import java.util.ArrayList;
33  import java.util.HashMap;
34  import java.util.List;
35  import java.util.Map;
36  
37  /**
38   * <a href="MethodInvoker.java.html"><b><i>View Source</i></b></a>
39   *
40   * @author Brian Wing Shun Chan
41   * @author Harry Mark
42   * @author Shuyang Zhou
43   */
44  public class MethodInvoker {
45  
46      public static Object invoke(MethodWrapper methodWrapper)
47          throws ClassNotFoundException, IllegalAccessException,
48                 InstantiationException, InvocationTargetException,
49                 NoSuchFieldException, NoSuchMethodException {
50  
51          return invoke(methodWrapper, true);
52      }
53  
54      public static Object invoke(
55              MethodWrapper methodWrapper, boolean newInstance)
56          throws ClassNotFoundException, IllegalAccessException,
57                 InstantiationException, InvocationTargetException,
58                 NoSuchFieldException, NoSuchMethodException {
59  
60          Object targetObject = null;
61  
62          if (newInstance) {
63              Thread currentThread = Thread.currentThread();
64  
65              ClassLoader contextClassLoader =
66                  currentThread.getContextClassLoader();
67  
68              targetObject = contextClassLoader.loadClass(
69                  methodWrapper.getClassName()).newInstance();
70          }
71  
72          Object[] methodAndArguments = _lookupMethodAndArguments(
73              methodWrapper, targetObject);
74  
75          Object returnObject = null;
76  
77          if (methodAndArguments[0] != null) {
78              Method method = (Method)methodAndArguments[0];
79              Object[] arguments = (Object[])methodAndArguments[1];
80  
81              returnObject = method.invoke(targetObject, arguments);
82          }
83  
84          return returnObject;
85      }
86  
87      public static Object invoke(
88              MethodWrapper methodWrapper, Object targetObject)
89          throws ClassNotFoundException, IllegalAccessException,
90                 InvocationTargetException, NoSuchFieldException,
91                 NoSuchMethodException {
92  
93          Object[] methodAndArguments = _lookupMethodAndArguments(
94              methodWrapper, targetObject);
95  
96          Object returnObject = null;
97  
98          if (methodAndArguments[0] != null) {
99              Method method = (Method)methodAndArguments[0];
100             Object[] arguments = (Object[])methodAndArguments[1];
101 
102             returnObject = method.invoke(targetObject, arguments);
103         }
104 
105         return returnObject;
106     }
107 
108     private static Object[] _lookupMethodAndArguments(
109             MethodWrapper methodWrapper, Object targetObject)
110         throws ClassNotFoundException, IllegalAccessException,
111                InvocationTargetException, NoSuchFieldException,
112                NoSuchMethodException {
113 
114         Object[] methodAndArguments = new Object[2];
115 
116         Thread currentThread = Thread.currentThread();
117 
118         ClassLoader contextClassLoader = currentThread.getContextClassLoader();
119 
120         String className = methodWrapper.getClassName();
121         String methodName = methodWrapper.getMethodName();
122         Object[] arguments = methodWrapper.getArguments();
123         String[] argumentClassNames = methodWrapper.getArgumentClassNames();
124 
125         List<Class<?>> parameterTypes = new ArrayList<Class<?>>();
126 
127         for (int i = 0; i < arguments.length; i++) {
128             if (arguments[i] == null) {
129                 _log.error(
130                     "Cannot invoke " + className + " " + methodName +
131                         " on position " + i + " because it is null");
132             }
133 
134             Class<?> argClass = null;
135 
136             if (argumentClassNames != null) {
137                 argClass = _primitiveTypeMap.get(argumentClassNames[i]);
138 
139                 if (argClass == null) {
140                     argClass = Class.forName(
141                         argumentClassNames[i], true, contextClassLoader);
142                 }
143             }
144             else {
145                 argClass = arguments[i].getClass();
146             }
147 
148             if (ClassUtil.isSubclass(argClass, PrimitiveWrapper.class)) {
149                 parameterTypes.add(
150                     (Class<?>)argClass.getField("TYPE").get(arguments[i]));
151 
152                 MethodKey methodKey = new MethodKey(
153                     argClass.getName(), "getValue", null);
154 
155                 Method method = MethodCache.get(methodKey);
156 
157                 arguments[i] = method.invoke(arguments[i], (Object[])null);
158             }
159             else if (arguments[i] instanceof NullWrapper) {
160                 NullWrapper nullWrapper = (NullWrapper)arguments[i];
161 
162                 String wrappedClassName = nullWrapper.getClassName();
163 
164                 if (wrappedClassName.startsWith(StringPool.OPEN_BRACKET) &&
165                     wrappedClassName.endsWith(StringPool.SEMICOLON)) {
166 
167                     wrappedClassName = wrappedClassName.substring(
168                         2, wrappedClassName.length() - 1);
169 
170                     Class<?> wrappedClass = contextClassLoader.loadClass(
171                         wrappedClassName);
172 
173                     parameterTypes.add(
174                         Array.newInstance(wrappedClass, 0).getClass());
175                 }
176                 else {
177                     Class<?> wrappedClass = contextClassLoader.loadClass(
178                         wrappedClassName);
179 
180                     parameterTypes.add(wrappedClass);
181                 }
182 
183                 arguments[i] = null;
184             }
185             else {
186                 parameterTypes.add(argClass);
187             }
188         }
189 
190         Method method = null;
191 
192         try {
193             MethodKey methodKey = new MethodKey(
194                 methodWrapper.getClassName(), methodWrapper.getMethodName(),
195                 parameterTypes.toArray(new Class[parameterTypes.size()]));
196 
197             method = MethodCache.get(methodKey);
198         }
199         catch (NoSuchMethodException nsme) {
200             Class<?> classObject = null;
201 
202             if (targetObject == null) {
203                 classObject = contextClassLoader.loadClass(className);
204             }
205             else {
206                 classObject = targetObject.getClass();
207             }
208 
209             Method[] methods = classObject.getMethods();
210 
211             for (int i = 0; i < methods.length; i++) {
212                 Class<?>[] methodParameterTypes =
213                     methods[i].getParameterTypes();
214 
215                 if (methods[i].getName().equals(methodName) &&
216                     methodParameterTypes.length == parameterTypes.size()) {
217 
218                     boolean correctParams = true;
219 
220                     for (int j = 0; j < parameterTypes.size(); j++) {
221                         Class<?> a = parameterTypes.get(j);
222                         Class<?> b = methodParameterTypes[j];
223 
224                         if (!ClassUtil.isSubclass(a, b)) {
225                             correctParams = false;
226 
227                             break;
228                         }
229                     }
230 
231                     if (correctParams) {
232                         method = methods[i];
233 
234                         break;
235                     }
236                 }
237             }
238 
239             if (method == null) {
240                 throw nsme;
241             }
242         }
243 
244         methodAndArguments[0] = method;
245         methodAndArguments[1] = arguments;
246 
247         return methodAndArguments;
248     }
249 
250     private static Log _log = LogFactoryUtil.getLog(MethodInvoker.class);
251 
252     private static Map<String, Class<?>> _primitiveTypeMap =
253         new HashMap<String, Class<?>>();
254 
255     static {
256         _primitiveTypeMap.put("char", char.class);
257         _primitiveTypeMap.put("boolean", boolean.class);
258         _primitiveTypeMap.put("byte", byte.class);
259         _primitiveTypeMap.put("double", double.class);
260         _primitiveTypeMap.put("float", float.class);
261         _primitiveTypeMap.put("int", int.class);
262         _primitiveTypeMap.put("long", long.class);
263         _primitiveTypeMap.put("short", short.class);
264     }
265 
266 }