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