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