1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions 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.action;
24  
25  import com.liferay.portal.kernel.json.JSONArray;
26  import com.liferay.portal.kernel.json.JSONFactoryUtil;
27  import com.liferay.portal.kernel.json.JSONObject;
28  import com.liferay.portal.kernel.log.Log;
29  import com.liferay.portal.kernel.log.LogFactoryUtil;
30  import com.liferay.portal.kernel.util.MethodInvoker;
31  import com.liferay.portal.kernel.util.MethodWrapper;
32  import com.liferay.portal.kernel.util.ParamUtil;
33  import com.liferay.portal.kernel.util.StringUtil;
34  import com.liferay.portal.kernel.util.Validator;
35  import com.liferay.portal.model.BaseModel;
36  import com.liferay.portal.struts.JSONAction;
37  import com.liferay.portlet.tags.model.TagsAssetDisplay;
38  import com.liferay.portlet.tags.model.TagsAssetType;
39  
40  import java.lang.reflect.InvocationTargetException;
41  import java.lang.reflect.Method;
42  
43  import java.util.Date;
44  import java.util.HashMap;
45  import java.util.List;
46  import java.util.Map;
47  
48  import javax.servlet.http.HttpServletRequest;
49  import javax.servlet.http.HttpServletResponse;
50  
51  import org.apache.struts.action.ActionForm;
52  import org.apache.struts.action.ActionMapping;
53  
54  /**
55   * <a href="JSONServiceAction.java.html"><b><i>View Source</i></b></a>
56   *
57   * @author Brian Wing Shun Chan
58   * @author Karthik Sudarshan
59   *
60   */
61  public class JSONServiceAction extends JSONAction {
62  
63      public static JSONObject toJSONObject(TagsAssetDisplay assetDisplay) {
64          JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
65  
66          jsonObj.put("assetId", assetDisplay.getAssetId());
67          jsonObj.put("companyId", assetDisplay.getCompanyId());
68          jsonObj.put("userId", assetDisplay.getUserId());
69          jsonObj.put("userName", assetDisplay.getUserName());
70          jsonObj.put("createDate", assetDisplay.getCreateDate());
71          jsonObj.put("modifiedDate", assetDisplay.getModifiedDate());
72          jsonObj.put("classNameId", assetDisplay.getClassNameId());
73          jsonObj.put("className", assetDisplay.getClassName());
74          jsonObj.put("classPK", assetDisplay.getClassPK());
75          jsonObj.put("portletId", assetDisplay.getPortletId());
76          jsonObj.put("portletTitle", assetDisplay.getPortletTitle());
77          jsonObj.put("startDate", assetDisplay.getStartDate());
78          jsonObj.put("endDate", assetDisplay.getEndDate());
79          jsonObj.put("publishDate", assetDisplay.getPublishDate());
80          jsonObj.put("expirationDate", assetDisplay.getExpirationDate());
81          jsonObj.put("mimeType", assetDisplay.getMimeType());
82          jsonObj.put("title", assetDisplay.getTitle());
83          jsonObj.put("description", assetDisplay.getDescription());
84          jsonObj.put("summary", assetDisplay.getSummary());
85          jsonObj.put("url", assetDisplay.getUrl());
86          jsonObj.put("height", assetDisplay.getHeight());
87          jsonObj.put("width", assetDisplay.getWidth());
88          jsonObj.put("priority", assetDisplay.getPriority());
89          jsonObj.put("viewCount", assetDisplay.getViewCount());
90          jsonObj.put("tagsEntries", assetDisplay.getTagsEntries());
91  
92          return jsonObj;
93      }
94  
95      public static JSONObject toJSONObject(TagsAssetType assetType) {
96          JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
97  
98          jsonObj.put("classNameId", assetType.getClassNameId());
99          jsonObj.put("className", assetType.getClassName());
100         jsonObj.put("portletId", assetType.getPortletId());
101         jsonObj.put("portletTitle", assetType.getPortletTitle());
102 
103         return jsonObj;
104     }
105 
106     public String getJSON(
107             ActionMapping mapping, ActionForm form, HttpServletRequest request,
108             HttpServletResponse response)
109         throws Exception {
110 
111         String className = ParamUtil.getString(request, "serviceClassName");
112         String methodName = ParamUtil.getString(request, "serviceMethodName");
113         String[] serviceParameters = StringUtil.split(
114             ParamUtil.getString(request, "serviceParameters"));
115         String[] serviceParameterTypes = StringUtil.split(
116             ParamUtil.getString(request, "serviceParameterTypes"));
117 
118         if (!isValidRequest(request)) {
119             return null;
120         }
121 
122         Class<?> classObj = Class.forName(className);
123 
124         Object[] methodAndParameterTypes = getMethodAndParameterTypes(
125             classObj, methodName, serviceParameters, serviceParameterTypes);
126 
127         if (methodAndParameterTypes != null) {
128             Method method = (Method)methodAndParameterTypes[0];
129             Class<?>[] parameterTypes = (Class[])methodAndParameterTypes[1];
130             Object[] args = new Object[serviceParameters.length];
131 
132             for (int i = 0; i < serviceParameters.length; i++) {
133                 args[i] = getArgValue(
134                     request, classObj, methodName, serviceParameters[i],
135                     parameterTypes[i]);
136 
137             }
138 
139             try {
140                 if (_log.isDebugEnabled()) {
141                     _log.debug(
142                         "Invoking class " + classObj + " on method " +
143                             method.getName() + " with args " + args);
144                 }
145 
146                 Object returnObj = method.invoke(classObj, args);
147 
148                 if (returnObj != null) {
149                     if (returnObj instanceof BaseModel) {
150                         String serlializerClassName = getSerializerClassName(
151                             returnObj);
152 
153                         MethodWrapper methodWrapper = new MethodWrapper(
154                             serlializerClassName, "toJSONObject", returnObj);
155 
156                         JSONObject jsonObj = (JSONObject)MethodInvoker.invoke(
157                             methodWrapper, false);
158 
159                         return jsonObj.toString();
160                     }
161                     else if (returnObj instanceof List) {
162                         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
163 
164                         List<Object> returnList = (List<Object>)returnObj;
165 
166                         if (!returnList.isEmpty()) {
167                             Object returnItem0 = returnList.get(0);
168 
169                             String serlializerClassName =
170                                 getSerializerClassName(returnItem0);
171 
172                             MethodWrapper methodWrapper = new MethodWrapper(
173                                 serlializerClassName, "toJSONArray", returnObj);
174 
175                             jsonArray = (JSONArray)MethodInvoker.invoke(
176                                 methodWrapper, false);
177                         }
178 
179                         return jsonArray.toString();
180                     }
181                     else if (returnObj instanceof JSONArray) {
182                         JSONArray jsonArray = (JSONArray)returnObj;
183 
184                         return jsonArray.toString();
185                     }
186                     else if (returnObj instanceof JSONObject) {
187                         JSONObject jsonObj = (JSONObject)returnObj;
188 
189                         return jsonObj.toString();
190                     }
191                     else if (returnObj instanceof Boolean ||
192                              returnObj instanceof Double ||
193                              returnObj instanceof Integer ||
194                              returnObj instanceof Long ||
195                              returnObj instanceof Short ||
196                              returnObj instanceof String) {
197 
198                         JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
199 
200                         jsonObj.put("returnValue", returnObj.toString());
201 
202                         return jsonObj.toString();
203                     }
204                     else {
205                         String returnValue = getReturnValue(returnObj);
206 
207                         if (returnValue == null) {
208                             _log.error(
209                                 "Unsupported return type for class " +
210                                     classObj + " and method " + methodName);
211                         }
212 
213                         return returnValue;
214                     }
215                 }
216                 else {
217                     JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
218 
219                     return jsonObj.toString();
220                 }
221             }
222             catch (Exception e) {
223                 JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
224 
225                 if (e instanceof InvocationTargetException) {
226                     jsonObj.put("exception", e.getCause().toString());
227                 }
228                 else {
229                     jsonObj.put("exception", e.getMessage());
230                 }
231 
232                 return jsonObj.toString();
233             }
234         }
235 
236         return null;
237     }
238 
239     protected Object getArgValue(
240             HttpServletRequest request, Class<?> classObj, String methodName,
241             String parameter, Class<?> parameterType)
242         throws Exception {
243 
244         String parameterTypeName = parameterType.getName();
245 
246         String value = ParamUtil.getString(request, parameter);
247 
248         if (Validator.isNull(value) &&
249             !parameterTypeName.equals("[Ljava.lang.String;")) {
250 
251             return null;
252         }
253         else if (parameterTypeName.equals("boolean") ||
254                  parameterTypeName.equals(Boolean.class.getName())) {
255 
256             return Boolean.valueOf(ParamUtil.getBoolean(request, parameter));
257         }
258         else if (parameterTypeName.equals("double") ||
259                  parameterTypeName.equals(Double.class.getName())) {
260 
261             return new Double(ParamUtil.getDouble(request, parameter));
262         }
263         else if (parameterTypeName.equals("int") ||
264                  parameterTypeName.equals(Integer.class.getName())) {
265 
266             return new Integer(ParamUtil.getInteger(request, parameter));
267         }
268         else if (parameterTypeName.equals("long") ||
269                  parameterTypeName.equals(Long.class.getName())) {
270 
271             return new Long(ParamUtil.getLong(request, parameter));
272         }
273         else if (parameterTypeName.equals("short") ||
274                  parameterTypeName.equals(Short.class.getName())) {
275 
276             return new Short(ParamUtil.getShort(request, parameter));
277         }
278         else if (parameterTypeName.equals(Date.class.getName())) {
279             return new Date(ParamUtil.getLong(request, parameter));
280         }
281         else if (parameterTypeName.equals(String.class.getName())) {
282             return value;
283         }
284         else if (parameterTypeName.equals("[Ljava.lang.String;")) {
285             return StringUtil.split(value);
286         }
287         else if (parameterTypeName.equals("[Z")) {
288             return ParamUtil.getBooleanValues(request, parameter);
289         }
290         else if (parameterTypeName.equals("[D")) {
291             return ParamUtil.getDoubleValues(request, parameter);
292         }
293         else if (parameterTypeName.equals("[F")) {
294             return ParamUtil.getFloatValues(request, parameter);
295         }
296         else if (parameterTypeName.equals("[I")) {
297             return ParamUtil.getIntegerValues(request, parameter);
298         }
299         else if (parameterTypeName.equals("[J")) {
300             return ParamUtil.getLongValues(request, parameter);
301         }
302         else if (parameterTypeName.equals("[S")) {
303             return ParamUtil.getShortValues(request, parameter);
304         }
305         else {
306             _log.error(
307                 "Unsupported parameter type for class " + classObj +
308                     ", method " + methodName + ", parameter " + parameter +
309                         ", and type " + parameterTypeName);
310 
311             return null;
312         }
313     }
314 
315     protected Object[] getMethodAndParameterTypes(
316             Class<?> classObj, String methodName, String[] parameters,
317             String[] parameterTypes)
318         throws Exception {
319 
320         String parameterNames = StringUtil.merge(parameters);
321 
322         String key =
323             classObj.getName() + "_METHOD_NAME_" + methodName +
324                 "_PARAMETERS_" + parameterNames;
325 
326         Object[] methodAndParameterTypes = _methodCache.get(key);
327 
328         if (methodAndParameterTypes != null) {
329             return methodAndParameterTypes;
330         }
331 
332         Method method = null;
333         Class<?>[] methodParameterTypes = null;
334 
335         Method[] methods = classObj.getMethods();
336 
337         for (int i = 0; i < methods.length; i++) {
338             Method curMethod = methods[i];
339 
340             if (curMethod.getName().equals(methodName)) {
341                 Class<?>[] curParameterTypes = curMethod.getParameterTypes();
342 
343                 if (curParameterTypes.length == parameters.length) {
344                     if ((parameterTypes.length > 0) &&
345                         (parameterTypes.length == curParameterTypes.length)) {
346 
347                         boolean match = true;
348 
349                         for (int j = 0; j < parameterTypes.length; j++) {
350                             String t1 = parameterTypes[j];
351                             String t2 = curParameterTypes[j].getName();
352 
353                             if (!t1.equals(t2)) {
354                                 match = false;
355                             }
356                         }
357 
358                         if (match) {
359                             method = curMethod;
360                             methodParameterTypes = curParameterTypes;
361 
362                             break;
363                         }
364                     }
365                     else if (method != null) {
366                         _log.error(
367                             "Obscure method name for class " + classObj +
368                                 ", method " + methodName + ", and parameters " +
369                                     parameterNames);
370 
371                         return null;
372                     }
373                     else {
374                         method = curMethod;
375                         methodParameterTypes = curParameterTypes;
376                     }
377                 }
378             }
379         }
380 
381         if (method != null) {
382             methodAndParameterTypes =
383                 new Object[] {method, methodParameterTypes};
384 
385             _methodCache.put(key, methodAndParameterTypes);
386 
387             return methodAndParameterTypes;
388         }
389         else {
390             _log.error(
391                 "No method found for class " + classObj + ", method " +
392                     methodName + ", and parameters " + parameterNames);
393 
394             return null;
395         }
396     }
397 
398     protected String getReturnValue(Object returnObj) throws Exception {
399         if (returnObj instanceof TagsAssetDisplay) {
400             return getReturnValue((TagsAssetDisplay)returnObj);
401         }
402         else if (returnObj instanceof TagsAssetDisplay[]) {
403             return getReturnValue((TagsAssetDisplay[])returnObj);
404         }
405         else if (returnObj instanceof TagsAssetType) {
406             return getReturnValue((TagsAssetType)returnObj);
407         }
408         else if (returnObj instanceof TagsAssetType[]) {
409             return getReturnValue((TagsAssetType[])returnObj);
410         }
411         else {
412             return JSONFactoryUtil.serialize(returnObj);
413         }
414     }
415 
416     protected String getReturnValue(TagsAssetDisplay assetDisplay)
417         throws Exception {
418 
419         JSONObject jsonObj = toJSONObject(assetDisplay);
420 
421         return jsonObj.toString();
422     }
423 
424     protected String getReturnValue(TagsAssetDisplay[] assetDisplays)
425         throws Exception {
426 
427         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
428 
429         for (int i = 0; i < assetDisplays.length; i++) {
430             TagsAssetDisplay assetDisplay = assetDisplays[i];
431 
432             jsonArray.put(toJSONObject(assetDisplay));
433         }
434 
435         return jsonArray.toString();
436     }
437 
438     protected String getReturnValue(TagsAssetType assetType)
439         throws Exception {
440 
441         JSONObject jsonObj = toJSONObject(assetType);
442 
443         return jsonObj.toString();
444     }
445 
446     protected String getReturnValue(TagsAssetType[] assetTypes)
447         throws Exception {
448 
449         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
450 
451         for (int i = 0; i < assetTypes.length; i++) {
452             TagsAssetType assetType = assetTypes[i];
453 
454             jsonArray.put(toJSONObject(assetType));
455         }
456 
457         return jsonArray.toString();
458     }
459 
460     protected String getSerializerClassName(Object obj) {
461         String serlializerClassName = StringUtil.replace(
462             obj.getClass().getName(),
463             new String[] {".model.impl.", "Impl"},
464             new String[] {".service.http.", "JSONSerializer"});
465 
466         return serlializerClassName;
467     }
468 
469     protected boolean isValidRequest(HttpServletRequest request) {
470         String className = ParamUtil.getString(request, "serviceClassName");
471 
472         if (className.contains(".service.") &&
473             className.endsWith("ServiceUtil") &&
474             !className.endsWith("LocalServiceUtil")) {
475 
476             return true;
477         }
478         else {
479             return false;
480         }
481     }
482 
483     private static Log _log = LogFactoryUtil.getLog(JSONServiceAction.class);
484 
485     private Map<String, Object[]> _methodCache =
486         new HashMap<String, Object[]>();
487 
488 }