1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    *
5    *
6    *
7    * The contents of this file are subject to the terms of the Liferay Enterprise
8    * Subscription License ("License"). You may not use this file except in
9    * compliance with the License. You can obtain a copy of the License by
10   * contacting Liferay, Inc. See the License for the specific language governing
11   * permissions and limitations under the License, including but not limited to
12   * distribution rights of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.action;
24  
25  import com.liferay.portal.kernel.json.JSONArray;
26  import com.liferay.portal.kernel.json.JSONException;
27  import com.liferay.portal.kernel.json.JSONFactoryUtil;
28  import com.liferay.portal.kernel.json.JSONObject;
29  import com.liferay.portal.kernel.log.Log;
30  import com.liferay.portal.kernel.log.LogFactoryUtil;
31  import com.liferay.portal.kernel.util.ArrayUtil;
32  import com.liferay.portal.kernel.util.GetterUtil;
33  import com.liferay.portal.kernel.util.MethodInvoker;
34  import com.liferay.portal.kernel.util.MethodWrapper;
35  import com.liferay.portal.kernel.util.ParamUtil;
36  import com.liferay.portal.kernel.util.StringUtil;
37  import com.liferay.portal.kernel.util.Validator;
38  import com.liferay.portal.model.BaseModel;
39  import com.liferay.portal.service.ServiceContext;
40  import com.liferay.portal.service.ServiceContextUtil;
41  import com.liferay.portal.struts.JSONAction;
42  import com.liferay.portlet.tags.model.TagsAssetDisplay;
43  import com.liferay.portlet.tags.model.TagsAssetType;
44  
45  import java.lang.reflect.InvocationTargetException;
46  import java.lang.reflect.Method;
47  
48  import java.util.Date;
49  import java.util.HashMap;
50  import java.util.List;
51  import java.util.Map;
52  
53  import javax.servlet.http.HttpServletRequest;
54  import javax.servlet.http.HttpServletResponse;
55  
56  import org.apache.struts.action.ActionForm;
57  import org.apache.struts.action.ActionMapping;
58  
59  /**
60   * <a href="JSONServiceAction.java.html"><b><i>View Source</i></b></a>
61   *
62   * @author Brian Wing Shun Chan
63   * @author Karthik Sudarshan
64   */
65  public class JSONServiceAction extends JSONAction {
66  
67      public static JSONObject toJSONObject(TagsAssetDisplay assetDisplay) {
68          JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
69  
70          jsonObj.put("assetId", assetDisplay.getAssetId());
71          jsonObj.put("companyId", assetDisplay.getCompanyId());
72          jsonObj.put("userId", assetDisplay.getUserId());
73          jsonObj.put("userName", assetDisplay.getUserName());
74          jsonObj.put("createDate", assetDisplay.getCreateDate());
75          jsonObj.put("modifiedDate", assetDisplay.getModifiedDate());
76          jsonObj.put("classNameId", assetDisplay.getClassNameId());
77          jsonObj.put("className", assetDisplay.getClassName());
78          jsonObj.put("classPK", assetDisplay.getClassPK());
79          jsonObj.put("portletId", assetDisplay.getPortletId());
80          jsonObj.put("portletTitle", assetDisplay.getPortletTitle());
81          jsonObj.put("startDate", assetDisplay.getStartDate());
82          jsonObj.put("endDate", assetDisplay.getEndDate());
83          jsonObj.put("publishDate", assetDisplay.getPublishDate());
84          jsonObj.put("expirationDate", assetDisplay.getExpirationDate());
85          jsonObj.put("mimeType", assetDisplay.getMimeType());
86          jsonObj.put("title", assetDisplay.getTitle());
87          jsonObj.put("description", assetDisplay.getDescription());
88          jsonObj.put("summary", assetDisplay.getSummary());
89          jsonObj.put("url", assetDisplay.getUrl());
90          jsonObj.put("height", assetDisplay.getHeight());
91          jsonObj.put("width", assetDisplay.getWidth());
92          jsonObj.put("priority", assetDisplay.getPriority());
93          jsonObj.put("viewCount", assetDisplay.getViewCount());
94          jsonObj.put("tagsEntries", assetDisplay.getTagsEntries());
95  
96          return jsonObj;
97      }
98  
99      public static JSONObject toJSONObject(TagsAssetType assetType) {
100         JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
101 
102         jsonObj.put("classNameId", assetType.getClassNameId());
103         jsonObj.put("className", assetType.getClassName());
104         jsonObj.put("portletId", assetType.getPortletId());
105         jsonObj.put("portletTitle", assetType.getPortletTitle());
106 
107         return jsonObj;
108     }
109 
110     public String getJSON(
111             ActionMapping mapping, ActionForm form, HttpServletRequest request,
112             HttpServletResponse response)
113         throws Exception {
114 
115         String className = ParamUtil.getString(request, "serviceClassName");
116         String methodName = ParamUtil.getString(request, "serviceMethodName");
117         String[] serviceParameters = getStringArrayFromJSON(
118             request, "serviceParameters");
119         String[] serviceParameterTypes = getStringArrayFromJSON(
120             request, "serviceParameterTypes");
121 
122         if (!isValidRequest(request)) {
123             return null;
124         }
125 
126         Class<?> classObj = Class.forName(className);
127 
128         Object[] methodAndParameterTypes = getMethodAndParameterTypes(
129             classObj, methodName, serviceParameters, serviceParameterTypes);
130 
131         if (methodAndParameterTypes != null) {
132             Method method = (Method)methodAndParameterTypes[0];
133             Class<?>[] parameterTypes = (Class[])methodAndParameterTypes[1];
134             Object[] args = new Object[serviceParameters.length];
135 
136             for (int i = 0; i < serviceParameters.length; i++) {
137                 args[i] = getArgValue(
138                     request, classObj, methodName, serviceParameters[i],
139                     parameterTypes[i]);
140             }
141 
142             try {
143                 if (_log.isDebugEnabled()) {
144                     _log.debug(
145                         "Invoking class " + classObj + " on method " +
146                             method.getName() + " with args " + args);
147                 }
148 
149                 Object returnObj = method.invoke(classObj, args);
150 
151                 if (returnObj != null) {
152                     return getReturnValue(returnObj);
153                 }
154                 else {
155                     JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
156 
157                     return jsonObj.toString();
158                 }
159             }
160             catch (Exception e) {
161                 if (_log.isDebugEnabled()) {
162                     _log.debug(
163                         "Invoked class " + classObj + " on method " +
164                             method.getName() + " with args " + args,
165                         e);
166                 }
167 
168                 JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
169 
170                 if (e instanceof InvocationTargetException) {
171                     jsonObj.put("exception", e.getCause().toString());
172                 }
173                 else {
174                     jsonObj.put("exception", e.getMessage());
175                 }
176 
177                 return jsonObj.toString();
178             }
179         }
180 
181         return null;
182     }
183 
184     protected Object getArgValue(
185             HttpServletRequest request, Class<?> classObj, String methodName,
186             String parameter, Class<?> parameterType)
187         throws Exception {
188 
189         String parameterTypeName = parameterType.getName();
190 
191         String value = ParamUtil.getString(request, parameter);
192 
193         if (Validator.isNull(value) &&
194             !parameterTypeName.equals("[Ljava.lang.String;")) {
195 
196             return null;
197         }
198         else if (parameterTypeName.equals("boolean") ||
199                  parameterTypeName.equals(Boolean.class.getName())) {
200 
201             return Boolean.valueOf(ParamUtil.getBoolean(request, parameter));
202         }
203         else if (parameterTypeName.equals("double") ||
204                  parameterTypeName.equals(Double.class.getName())) {
205 
206             return new Double(ParamUtil.getDouble(request, parameter));
207         }
208         else if (parameterTypeName.equals("int") ||
209                  parameterTypeName.equals(Integer.class.getName())) {
210 
211             return new Integer(ParamUtil.getInteger(request, parameter));
212         }
213         else if (parameterTypeName.equals("long") ||
214                  parameterTypeName.equals(Long.class.getName())) {
215 
216             return new Long(ParamUtil.getLong(request, parameter));
217         }
218         else if (parameterTypeName.equals("short") ||
219                  parameterTypeName.equals(Short.class.getName())) {
220 
221             return new Short(ParamUtil.getShort(request, parameter));
222         }
223         else if (parameterTypeName.equals(Date.class.getName())) {
224             return new Date(ParamUtil.getLong(request, parameter));
225         }
226         else if (parameterTypeName.equals(ServiceContext.class.getName())) {
227             JSONObject jsonObject = JSONFactoryUtil.createJSONObject(value);
228 
229             jsonObject.put("javaClass", ServiceContext.class.getName());
230 
231             return ServiceContextUtil.deserialize(jsonObject);
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 
689             return true;
690         }
691         else {
692             return false;
693         }
694     }
695 
696     private static Log _log = LogFactoryUtil.getLog(JSONServiceAction.class);
697 
698     private Map<String, Object[]> _methodCache =
699         new HashMap<String, Object[]>();
700 
701 }