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.GetterUtil;
31  import com.liferay.portal.kernel.util.MethodInvoker;
32  import com.liferay.portal.kernel.util.MethodWrapper;
33  import com.liferay.portal.kernel.util.ParamUtil;
34  import com.liferay.portal.kernel.util.StringUtil;
35  import com.liferay.portal.kernel.util.Validator;
36  import com.liferay.portal.model.BaseModel;
37  import com.liferay.portal.struts.JSONAction;
38  import com.liferay.portlet.tags.model.TagsAssetDisplay;
39  import com.liferay.portlet.tags.model.TagsAssetType;
40  
41  import java.lang.reflect.InvocationTargetException;
42  import java.lang.reflect.Method;
43  
44  import java.util.Date;
45  import java.util.HashMap;
46  import java.util.List;
47  import java.util.Map;
48  
49  import javax.servlet.http.HttpServletRequest;
50  import javax.servlet.http.HttpServletResponse;
51  
52  import org.apache.struts.action.ActionForm;
53  import org.apache.struts.action.ActionMapping;
54  
55  /**
56   * <a href="JSONServiceAction.java.html"><b><i>View Source</i></b></a>
57   *
58   * @author Brian Wing Shun Chan
59   * @author Karthik Sudarshan
60   *
61   */
62  public class JSONServiceAction extends JSONAction {
63  
64      public static JSONObject toJSONObject(TagsAssetDisplay assetDisplay) {
65          JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
66  
67          jsonObj.put("assetId", assetDisplay.getAssetId());
68          jsonObj.put("companyId", assetDisplay.getCompanyId());
69          jsonObj.put("userId", assetDisplay.getUserId());
70          jsonObj.put("userName", assetDisplay.getUserName());
71          jsonObj.put("createDate", assetDisplay.getCreateDate());
72          jsonObj.put("modifiedDate", assetDisplay.getModifiedDate());
73          jsonObj.put("classNameId", assetDisplay.getClassNameId());
74          jsonObj.put("className", assetDisplay.getClassName());
75          jsonObj.put("classPK", assetDisplay.getClassPK());
76          jsonObj.put("portletId", assetDisplay.getPortletId());
77          jsonObj.put("portletTitle", assetDisplay.getPortletTitle());
78          jsonObj.put("startDate", assetDisplay.getStartDate());
79          jsonObj.put("endDate", assetDisplay.getEndDate());
80          jsonObj.put("publishDate", assetDisplay.getPublishDate());
81          jsonObj.put("expirationDate", assetDisplay.getExpirationDate());
82          jsonObj.put("mimeType", assetDisplay.getMimeType());
83          jsonObj.put("title", assetDisplay.getTitle());
84          jsonObj.put("description", assetDisplay.getDescription());
85          jsonObj.put("summary", assetDisplay.getSummary());
86          jsonObj.put("url", assetDisplay.getUrl());
87          jsonObj.put("height", assetDisplay.getHeight());
88          jsonObj.put("width", assetDisplay.getWidth());
89          jsonObj.put("priority", assetDisplay.getPriority());
90          jsonObj.put("viewCount", assetDisplay.getViewCount());
91          jsonObj.put("tagsEntries", assetDisplay.getTagsEntries());
92  
93          return jsonObj;
94      }
95  
96      public static JSONObject toJSONObject(TagsAssetType assetType) {
97          JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
98  
99          jsonObj.put("classNameId", assetType.getClassNameId());
100         jsonObj.put("className", assetType.getClassName());
101         jsonObj.put("portletId", assetType.getPortletId());
102         jsonObj.put("portletTitle", assetType.getPortletTitle());
103 
104         return jsonObj;
105     }
106 
107     public String getJSON(
108             ActionMapping mapping, ActionForm form, HttpServletRequest request,
109             HttpServletResponse response)
110         throws Exception {
111 
112         String className = ParamUtil.getString(request, "serviceClassName");
113         String methodName = ParamUtil.getString(request, "serviceMethodName");
114         String[] serviceParameters = StringUtil.split(
115             ParamUtil.getString(request, "serviceParameters"));
116         String[] serviceParameterTypes = StringUtil.split(
117             ParamUtil.getString(request, "serviceParameterTypes"));
118 
119         if (!isValidRequest(request)) {
120             return null;
121         }
122 
123         Class<?> classObj = Class.forName(className);
124 
125         Object[] methodAndParameterTypes = getMethodAndParameterTypes(
126             classObj, methodName, serviceParameters, serviceParameterTypes);
127 
128         if (methodAndParameterTypes != null) {
129             Method method = (Method)methodAndParameterTypes[0];
130             Class<?>[] parameterTypes = (Class[])methodAndParameterTypes[1];
131             Object[] args = new Object[serviceParameters.length];
132 
133             for (int i = 0; i < serviceParameters.length; i++) {
134                 args[i] = getArgValue(
135                     request, classObj, methodName, serviceParameters[i],
136                     parameterTypes[i]);
137 
138             }
139 
140             try {
141                 if (_log.isDebugEnabled()) {
142                     _log.debug(
143                         "Invoking class " + classObj + " on method " +
144                             method.getName() + " with args " + args);
145                 }
146 
147                 Object returnObj = method.invoke(classObj, args);
148 
149                 if (returnObj != null) {
150                     return getReturnValue(returnObj);
151                 }
152                 else {
153                     JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
154 
155                     return jsonObj.toString();
156                 }
157             }
158             catch (Exception e) {
159                 _log.error(e, e);
160 
161                 JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
162 
163                 if (e instanceof InvocationTargetException) {
164                     jsonObj.put("exception", e.getCause().toString());
165                 }
166                 else {
167                     jsonObj.put("exception", e.getMessage());
168                 }
169 
170                 return jsonObj.toString();
171             }
172         }
173 
174         return null;
175     }
176 
177     protected Object getArgValue(
178             HttpServletRequest request, Class<?> classObj, String methodName,
179             String parameter, Class<?> parameterType)
180         throws Exception {
181 
182         String parameterTypeName = parameterType.getName();
183 
184         String value = ParamUtil.getString(request, parameter);
185 
186         if (Validator.isNull(value) &&
187             !parameterTypeName.equals("[Ljava.lang.String;")) {
188 
189             return null;
190         }
191         else if (parameterTypeName.equals("boolean") ||
192                  parameterTypeName.equals(Boolean.class.getName())) {
193 
194             return Boolean.valueOf(ParamUtil.getBoolean(request, parameter));
195         }
196         else if (parameterTypeName.equals("double") ||
197                  parameterTypeName.equals(Double.class.getName())) {
198 
199             return new Double(ParamUtil.getDouble(request, parameter));
200         }
201         else if (parameterTypeName.equals("int") ||
202                  parameterTypeName.equals(Integer.class.getName())) {
203 
204             return new Integer(ParamUtil.getInteger(request, parameter));
205         }
206         else if (parameterTypeName.equals("long") ||
207                  parameterTypeName.equals(Long.class.getName())) {
208 
209             return new Long(ParamUtil.getLong(request, parameter));
210         }
211         else if (parameterTypeName.equals("short") ||
212                  parameterTypeName.equals(Short.class.getName())) {
213 
214             return new Short(ParamUtil.getShort(request, parameter));
215         }
216         else if (parameterTypeName.equals(Date.class.getName())) {
217             return new Date(ParamUtil.getLong(request, parameter));
218         }
219         else if (parameterTypeName.equals(String.class.getName())) {
220             return value;
221         }
222         else if (parameterTypeName.equals("[Z")) {
223             return ParamUtil.getBooleanValues(request, parameter);
224         }
225         else if (parameterTypeName.equals("[D")) {
226             return ParamUtil.getDoubleValues(request, parameter);
227         }
228         else if (parameterTypeName.equals("[F")) {
229             return ParamUtil.getFloatValues(request, parameter);
230         }
231         else if (parameterTypeName.equals("[I")) {
232             return ParamUtil.getIntegerValues(request, parameter);
233         }
234         else if (parameterTypeName.equals("[J")) {
235             return ParamUtil.getLongValues(request, parameter);
236         }
237         else if (parameterTypeName.equals("[S")) {
238             return ParamUtil.getShortValues(request, parameter);
239         }
240         else if (parameterTypeName.equals("[Ljava.lang.String;")) {
241             return StringUtil.split(value);
242         }
243         else if (parameterTypeName.equals("[[Z")) {
244             String[] values = request.getParameterValues(parameter);
245 
246             if ((values != null) && (values.length > 0)) {
247                 String[] values0 = StringUtil.split(values[0]);
248 
249                 boolean[][] doubleArray =
250                     new boolean[values.length][values0.length];
251 
252                 for (int i = 0; i < values.length; i++) {
253                     String[] curValues = StringUtil.split(values[i]);
254 
255                     for (int j = 0; j < curValues.length; j++) {
256                         doubleArray[i][j] = GetterUtil.getBoolean(curValues[j]);
257                     }
258                 }
259 
260                 return doubleArray;
261             }
262             else {
263                 return new boolean[0][0];
264             }
265         }
266         else if (parameterTypeName.equals("[[D")) {
267             String[] values = request.getParameterValues(parameter);
268 
269             if ((values != null) && (values.length > 0)) {
270                 String[] values0 = StringUtil.split(values[0]);
271 
272                 double[][] doubleArray =
273                     new double[values.length][values0.length];
274 
275                 for (int i = 0; i < values.length; i++) {
276                     String[] curValues = StringUtil.split(values[i]);
277 
278                     for (int j = 0; j < curValues.length; j++) {
279                         doubleArray[i][j] = GetterUtil.getDouble(curValues[j]);
280                     }
281                 }
282 
283                 return doubleArray;
284             }
285             else {
286                 return new double[0][0];
287             }
288         }
289         else if (parameterTypeName.equals("[[F")) {
290             String[] values = request.getParameterValues(parameter);
291 
292             if ((values != null) && (values.length > 0)) {
293                 String[] values0 = StringUtil.split(values[0]);
294 
295                 float[][] doubleArray =
296                     new float[values.length][values0.length];
297 
298                 for (int i = 0; i < values.length; i++) {
299                     String[] curValues = StringUtil.split(values[i]);
300 
301                     for (int j = 0; j < curValues.length; j++) {
302                         doubleArray[i][j] = GetterUtil.getFloat(curValues[j]);
303                     }
304                 }
305 
306                 return doubleArray;
307             }
308             else {
309                 return new float[0][0];
310             }
311         }
312         else if (parameterTypeName.equals("[[I")) {
313             String[] values = request.getParameterValues(parameter);
314 
315             if ((values != null) && (values.length > 0)) {
316                 String[] values0 = StringUtil.split(values[0]);
317 
318                 int[][] doubleArray =
319                     new int[values.length][values0.length];
320 
321                 for (int i = 0; i < values.length; i++) {
322                     String[] curValues = StringUtil.split(values[i]);
323 
324                     for (int j = 0; j < curValues.length; j++) {
325                         doubleArray[i][j] = GetterUtil.getInteger(curValues[j]);
326                     }
327                 }
328 
329                 return doubleArray;
330             }
331             else {
332                 return new int[0][0];
333             }
334         }
335         else if (parameterTypeName.equals("[[J")) {
336             String[] values = request.getParameterValues(parameter);
337 
338             if ((values != null) && (values.length > 0)) {
339                 String[] values0 = StringUtil.split(values[0]);
340 
341                 long[][] doubleArray =
342                     new long[values.length][values0.length];
343 
344                 for (int i = 0; i < values.length; i++) {
345                     String[] curValues = StringUtil.split(values[i]);
346 
347                     for (int j = 0; j < curValues.length; j++) {
348                         doubleArray[i][j] = GetterUtil.getLong(curValues[j]);
349                     }
350                 }
351 
352                 return doubleArray;
353             }
354             else {
355                 return new long[0][0];
356             }
357         }
358         else if (parameterTypeName.equals("[[S")) {
359             String[] values = request.getParameterValues(parameter);
360 
361             if ((values != null) && (values.length > 0)) {
362                 String[] values0 = StringUtil.split(values[0]);
363 
364                 short[][] doubleArray =
365                     new short[values.length][values0.length];
366 
367                 for (int i = 0; i < values.length; i++) {
368                     String[] curValues = StringUtil.split(values[i]);
369 
370                     for (int j = 0; j < curValues.length; j++) {
371                         doubleArray[i][j] = GetterUtil.getShort(curValues[j]);
372                     }
373                 }
374 
375                 return doubleArray;
376             }
377             else {
378                 return new short[0][0];
379             }
380         }
381         else if (parameterTypeName.equals("[[Ljava.lang.String")) {
382             String[] values = request.getParameterValues(parameter);
383 
384             if ((values != null) && (values.length > 0)) {
385                 String[] values0 = StringUtil.split(values[0]);
386 
387                 String[][] doubleArray =
388                     new String[values.length][values0.length];
389 
390                 for (int i = 0; i < values.length; i++) {
391                     doubleArray[i] = StringUtil.split(values[i]);
392                 }
393 
394                 return doubleArray;
395             }
396             else {
397                 return new String[0][0];
398             }
399         }
400         else {
401             _log.error(
402                 "Unsupported parameter type for class " + classObj +
403                     ", method " + methodName + ", parameter " + parameter +
404                         ", and type " + parameterTypeName);
405 
406             return null;
407         }
408     }
409 
410     protected Object[] getMethodAndParameterTypes(
411             Class<?> classObj, String methodName, String[] parameters,
412             String[] parameterTypes)
413         throws Exception {
414 
415         String parameterNames = StringUtil.merge(parameters);
416 
417         String key =
418             classObj.getName() + "_METHOD_NAME_" + methodName +
419                 "_PARAMETERS_" + parameterNames;
420 
421         Object[] methodAndParameterTypes = _methodCache.get(key);
422 
423         if (methodAndParameterTypes != null) {
424             return methodAndParameterTypes;
425         }
426 
427         Method method = null;
428         Class<?>[] methodParameterTypes = null;
429 
430         Method[] methods = classObj.getMethods();
431 
432         for (int i = 0; i < methods.length; i++) {
433             Method curMethod = methods[i];
434 
435             if (curMethod.getName().equals(methodName)) {
436                 Class<?>[] curParameterTypes = curMethod.getParameterTypes();
437 
438                 if (curParameterTypes.length == parameters.length) {
439                     if ((parameterTypes.length > 0) &&
440                         (parameterTypes.length == curParameterTypes.length)) {
441 
442                         boolean match = true;
443 
444                         for (int j = 0; j < parameterTypes.length; j++) {
445                             String t1 = parameterTypes[j];
446                             String t2 = curParameterTypes[j].getName();
447 
448                             if (!t1.equals(t2)) {
449                                 match = false;
450                             }
451                         }
452 
453                         if (match) {
454                             method = curMethod;
455                             methodParameterTypes = curParameterTypes;
456 
457                             break;
458                         }
459                     }
460                     else if (method != null) {
461                         _log.error(
462                             "Obscure method name for class " + classObj +
463                                 ", method " + methodName + ", and parameters " +
464                                     parameterNames);
465 
466                         return null;
467                     }
468                     else {
469                         method = curMethod;
470                         methodParameterTypes = curParameterTypes;
471                     }
472                 }
473             }
474         }
475 
476         if (method != null) {
477             methodAndParameterTypes =
478                 new Object[] {method, methodParameterTypes};
479 
480             _methodCache.put(key, methodAndParameterTypes);
481 
482             return methodAndParameterTypes;
483         }
484         else {
485             _log.error(
486                 "No method found for class " + classObj + ", method " +
487                     methodName + ", and parameters " + parameterNames);
488 
489             return null;
490         }
491     }
492 
493     protected String getReturnValue(Object returnObj) throws Exception {
494         if ((returnObj instanceof Boolean) || (returnObj instanceof Double) ||
495             (returnObj instanceof Integer) || (returnObj instanceof Long) ||
496             (returnObj instanceof Short) || (returnObj instanceof String)) {
497 
498             JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
499 
500             jsonObj.put("returnValue", returnObj.toString());
501 
502             return jsonObj.toString();
503         }
504         else if (returnObj instanceof BaseModel) {
505             String serlializerClassName = getSerializerClassName(returnObj);
506 
507             MethodWrapper methodWrapper = new MethodWrapper(
508                 serlializerClassName, "toJSONObject", returnObj);
509 
510             JSONObject jsonObj = (JSONObject)MethodInvoker.invoke(
511                 methodWrapper, false);
512 
513             return jsonObj.toString();
514         }
515         else if (returnObj instanceof BaseModel[]) {
516             JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
517 
518             BaseModel<?>[] returnArray = (BaseModel[])returnObj;
519 
520             if (returnArray.length > 0) {
521                 BaseModel<?> returnItem0 = returnArray[0];
522 
523                 String serializerClassName = getSerializerClassName(
524                     returnItem0);
525 
526                 MethodWrapper methodWrapper = new MethodWrapper(
527                     serializerClassName, "toJSONArray", returnObj);
528 
529                 jsonArray = (JSONArray)MethodInvoker.invoke(
530                     methodWrapper, false);
531             }
532 
533             return jsonArray.toString();
534         }
535         else if (returnObj instanceof BaseModel[][]) {
536             JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
537 
538             BaseModel<?>[][] returnArray = (BaseModel[][])returnObj;
539 
540             if ((returnArray.length > 0) &&
541                 (returnArray[0].length > 0)) {
542 
543                 BaseModel<?> returnItem0 = returnArray[0][0];
544 
545                 String serializerClassName = getSerializerClassName(
546                     returnItem0);
547 
548                 MethodWrapper methodWrapper = new MethodWrapper(
549                     serializerClassName, "toJSONArray", returnObj);
550 
551                 jsonArray = (JSONArray)MethodInvoker.invoke(
552                     methodWrapper, false);
553             }
554 
555             return jsonArray.toString();
556         }
557         else if (returnObj instanceof List) {
558             JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
559 
560             List<Object> returnList = (List<Object>)returnObj;
561 
562             if (!returnList.isEmpty()) {
563                 Object returnItem0 = returnList.get(0);
564 
565                 String serlializerClassName = getSerializerClassName(
566                     returnItem0);
567 
568                 MethodWrapper methodWrapper = new MethodWrapper(
569                     serlializerClassName, "toJSONArray", returnObj);
570 
571                 jsonArray = (JSONArray)MethodInvoker.invoke(
572                     methodWrapper, false);
573             }
574 
575             return jsonArray.toString();
576         }
577         else if (returnObj instanceof JSONArray) {
578             JSONArray jsonArray = (JSONArray)returnObj;
579 
580             return jsonArray.toString();
581         }
582         else if (returnObj instanceof JSONObject) {
583             JSONObject jsonObj = (JSONObject)returnObj;
584 
585             return jsonObj.toString();
586         }
587         else if (returnObj instanceof TagsAssetDisplay) {
588             return getReturnValue((TagsAssetDisplay)returnObj);
589         }
590         else if (returnObj instanceof TagsAssetDisplay[]) {
591             return getReturnValue((TagsAssetDisplay[])returnObj);
592         }
593         else if (returnObj instanceof TagsAssetType) {
594             return getReturnValue((TagsAssetType)returnObj);
595         }
596         else if (returnObj instanceof TagsAssetType[]) {
597             return getReturnValue((TagsAssetType[])returnObj);
598         }
599         else {
600             return JSONFactoryUtil.serialize(returnObj);
601         }
602     }
603 
604     protected String getReturnValue(TagsAssetDisplay assetDisplay)
605         throws Exception {
606 
607         JSONObject jsonObj = toJSONObject(assetDisplay);
608 
609         return jsonObj.toString();
610     }
611 
612     protected String getReturnValue(TagsAssetDisplay[] assetDisplays)
613         throws Exception {
614 
615         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
616 
617         for (int i = 0; i < assetDisplays.length; i++) {
618             TagsAssetDisplay assetDisplay = assetDisplays[i];
619 
620             jsonArray.put(toJSONObject(assetDisplay));
621         }
622 
623         return jsonArray.toString();
624     }
625 
626     protected String getReturnValue(TagsAssetType assetType)
627         throws Exception {
628 
629         JSONObject jsonObj = toJSONObject(assetType);
630 
631         return jsonObj.toString();
632     }
633 
634     protected String getReturnValue(TagsAssetType[] assetTypes)
635         throws Exception {
636 
637         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
638 
639         for (int i = 0; i < assetTypes.length; i++) {
640             TagsAssetType assetType = assetTypes[i];
641 
642             jsonArray.put(toJSONObject(assetType));
643         }
644 
645         return jsonArray.toString();
646     }
647 
648     protected String getSerializerClassName(Object obj) {
649         String serlializerClassName = StringUtil.replace(
650             obj.getClass().getName(),
651             new String[] {".model.impl.", "Impl"},
652             new String[] {".service.http.", "JSONSerializer"});
653 
654         return serlializerClassName;
655     }
656 
657     protected boolean isValidRequest(HttpServletRequest request) {
658         String className = ParamUtil.getString(request, "serviceClassName");
659 
660         if (className.contains(".service.") &&
661             className.endsWith("ServiceUtil") &&
662             !className.endsWith("LocalServiceUtil")) {
663 
664             return true;
665         }
666         else {
667             return false;
668         }
669     }
670 
671     private static Log _log = LogFactoryUtil.getLog(JSONServiceAction.class);
672 
673     private Map<String, Object[]> _methodCache =
674         new HashMap<String, Object[]>();
675 
676 }