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                 _log.error(e, e);
162 
163                 JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
164 
165                 if (e instanceof InvocationTargetException) {
166                     jsonObj.put("exception", e.getCause().toString());
167                 }
168                 else {
169                     jsonObj.put("exception", e.getMessage());
170                 }
171 
172                 return jsonObj.toString();
173             }
174         }
175 
176         return null;
177     }
178 
179     protected Object getArgValue(
180             HttpServletRequest request, Class<?> classObj, String methodName,
181             String parameter, Class<?> parameterType)
182         throws Exception {
183 
184         String parameterTypeName = parameterType.getName();
185 
186         String value = ParamUtil.getString(request, parameter);
187 
188         if (Validator.isNull(value) &&
189             !parameterTypeName.equals("[Ljava.lang.String;")) {
190 
191             return null;
192         }
193         else if (parameterTypeName.equals("boolean") ||
194                  parameterTypeName.equals(Boolean.class.getName())) {
195 
196             return Boolean.valueOf(ParamUtil.getBoolean(request, parameter));
197         }
198         else if (parameterTypeName.equals("double") ||
199                  parameterTypeName.equals(Double.class.getName())) {
200 
201             return new Double(ParamUtil.getDouble(request, parameter));
202         }
203         else if (parameterTypeName.equals("int") ||
204                  parameterTypeName.equals(Integer.class.getName())) {
205 
206             return new Integer(ParamUtil.getInteger(request, parameter));
207         }
208         else if (parameterTypeName.equals("long") ||
209                  parameterTypeName.equals(Long.class.getName())) {
210 
211             return new Long(ParamUtil.getLong(request, parameter));
212         }
213         else if (parameterTypeName.equals("short") ||
214                  parameterTypeName.equals(Short.class.getName())) {
215 
216             return new Short(ParamUtil.getShort(request, parameter));
217         }
218         else if (parameterTypeName.equals(Date.class.getName())) {
219             return new Date(ParamUtil.getLong(request, parameter));
220         }
221         else if (parameterTypeName.equals(ServiceContext.class.getName())) {
222             JSONObject jsonObject = JSONFactoryUtil.createJSONObject(value);
223 
224             jsonObject.put("javaClass", ServiceContext.class.getName());
225 
226             return ServiceContextUtil.deserialize(jsonObject);
227         }
228         else if (parameterTypeName.equals(String.class.getName())) {
229             return value;
230         }
231         else if (parameterTypeName.equals("[Z")) {
232             return ParamUtil.getBooleanValues(request, parameter);
233         }
234         else if (parameterTypeName.equals("[D")) {
235             return ParamUtil.getDoubleValues(request, parameter);
236         }
237         else if (parameterTypeName.equals("[F")) {
238             return ParamUtil.getFloatValues(request, parameter);
239         }
240         else if (parameterTypeName.equals("[I")) {
241             return ParamUtil.getIntegerValues(request, parameter);
242         }
243         else if (parameterTypeName.equals("[J")) {
244             return ParamUtil.getLongValues(request, parameter);
245         }
246         else if (parameterTypeName.equals("[S")) {
247             return ParamUtil.getShortValues(request, parameter);
248         }
249         else if (parameterTypeName.equals("[Ljava.lang.String;")) {
250             return StringUtil.split(value);
251         }
252         else if (parameterTypeName.equals("[[Z")) {
253             String[] values = request.getParameterValues(parameter);
254 
255             if ((values != null) && (values.length > 0)) {
256                 String[] values0 = StringUtil.split(values[0]);
257 
258                 boolean[][] doubleArray =
259                     new boolean[values.length][values0.length];
260 
261                 for (int i = 0; i < values.length; i++) {
262                     String[] curValues = StringUtil.split(values[i]);
263 
264                     for (int j = 0; j < curValues.length; j++) {
265                         doubleArray[i][j] = GetterUtil.getBoolean(curValues[j]);
266                     }
267                 }
268 
269                 return doubleArray;
270             }
271             else {
272                 return new boolean[0][0];
273             }
274         }
275         else if (parameterTypeName.equals("[[D")) {
276             String[] values = request.getParameterValues(parameter);
277 
278             if ((values != null) && (values.length > 0)) {
279                 String[] values0 = StringUtil.split(values[0]);
280 
281                 double[][] doubleArray =
282                     new double[values.length][values0.length];
283 
284                 for (int i = 0; i < values.length; i++) {
285                     String[] curValues = StringUtil.split(values[i]);
286 
287                     for (int j = 0; j < curValues.length; j++) {
288                         doubleArray[i][j] = GetterUtil.getDouble(curValues[j]);
289                     }
290                 }
291 
292                 return doubleArray;
293             }
294             else {
295                 return new double[0][0];
296             }
297         }
298         else if (parameterTypeName.equals("[[F")) {
299             String[] values = request.getParameterValues(parameter);
300 
301             if ((values != null) && (values.length > 0)) {
302                 String[] values0 = StringUtil.split(values[0]);
303 
304                 float[][] doubleArray =
305                     new float[values.length][values0.length];
306 
307                 for (int i = 0; i < values.length; i++) {
308                     String[] curValues = StringUtil.split(values[i]);
309 
310                     for (int j = 0; j < curValues.length; j++) {
311                         doubleArray[i][j] = GetterUtil.getFloat(curValues[j]);
312                     }
313                 }
314 
315                 return doubleArray;
316             }
317             else {
318                 return new float[0][0];
319             }
320         }
321         else if (parameterTypeName.equals("[[I")) {
322             String[] values = request.getParameterValues(parameter);
323 
324             if ((values != null) && (values.length > 0)) {
325                 String[] values0 = StringUtil.split(values[0]);
326 
327                 int[][] doubleArray =
328                     new int[values.length][values0.length];
329 
330                 for (int i = 0; i < values.length; i++) {
331                     String[] curValues = StringUtil.split(values[i]);
332 
333                     for (int j = 0; j < curValues.length; j++) {
334                         doubleArray[i][j] = GetterUtil.getInteger(curValues[j]);
335                     }
336                 }
337 
338                 return doubleArray;
339             }
340             else {
341                 return new int[0][0];
342             }
343         }
344         else if (parameterTypeName.equals("[[J")) {
345             String[] values = request.getParameterValues(parameter);
346 
347             if ((values != null) && (values.length > 0)) {
348                 String[] values0 = StringUtil.split(values[0]);
349 
350                 long[][] doubleArray =
351                     new long[values.length][values0.length];
352 
353                 for (int i = 0; i < values.length; i++) {
354                     String[] curValues = StringUtil.split(values[i]);
355 
356                     for (int j = 0; j < curValues.length; j++) {
357                         doubleArray[i][j] = GetterUtil.getLong(curValues[j]);
358                     }
359                 }
360 
361                 return doubleArray;
362             }
363             else {
364                 return new long[0][0];
365             }
366         }
367         else if (parameterTypeName.equals("[[S")) {
368             String[] values = request.getParameterValues(parameter);
369 
370             if ((values != null) && (values.length > 0)) {
371                 String[] values0 = StringUtil.split(values[0]);
372 
373                 short[][] doubleArray =
374                     new short[values.length][values0.length];
375 
376                 for (int i = 0; i < values.length; i++) {
377                     String[] curValues = StringUtil.split(values[i]);
378 
379                     for (int j = 0; j < curValues.length; j++) {
380                         doubleArray[i][j] = GetterUtil.getShort(curValues[j]);
381                     }
382                 }
383 
384                 return doubleArray;
385             }
386             else {
387                 return new short[0][0];
388             }
389         }
390         else if (parameterTypeName.equals("[[Ljava.lang.String")) {
391             String[] values = request.getParameterValues(parameter);
392 
393             if ((values != null) && (values.length > 0)) {
394                 String[] values0 = StringUtil.split(values[0]);
395 
396                 String[][] doubleArray =
397                     new String[values.length][values0.length];
398 
399                 for (int i = 0; i < values.length; i++) {
400                     doubleArray[i] = StringUtil.split(values[i]);
401                 }
402 
403                 return doubleArray;
404             }
405             else {
406                 return new String[0][0];
407             }
408         }
409         else {
410             _log.error(
411                 "Unsupported parameter type for class " + classObj +
412                     ", method " + methodName + ", parameter " + parameter +
413                         ", and type " + parameterTypeName);
414 
415             return null;
416         }
417     }
418 
419     protected Object[] getMethodAndParameterTypes(
420             Class<?> classObj, String methodName, String[] parameters,
421             String[] parameterTypes)
422         throws Exception {
423 
424         String parameterNames = StringUtil.merge(parameters);
425 
426         String key =
427             classObj.getName() + "_METHOD_NAME_" + methodName +
428                 "_PARAMETERS_" + parameterNames;
429 
430         Object[] methodAndParameterTypes = _methodCache.get(key);
431 
432         if (methodAndParameterTypes != null) {
433             return methodAndParameterTypes;
434         }
435 
436         Method method = null;
437         Class<?>[] methodParameterTypes = null;
438 
439         Method[] methods = classObj.getMethods();
440 
441         for (int i = 0; i < methods.length; i++) {
442             Method curMethod = methods[i];
443 
444             if (curMethod.getName().equals(methodName)) {
445                 Class<?>[] curParameterTypes = curMethod.getParameterTypes();
446 
447                 if (curParameterTypes.length == parameters.length) {
448                     if ((parameterTypes.length > 0) &&
449                         (parameterTypes.length == curParameterTypes.length)) {
450 
451                         boolean match = true;
452 
453                         for (int j = 0; j < parameterTypes.length; j++) {
454                             String t1 = parameterTypes[j];
455                             String t2 = curParameterTypes[j].getName();
456 
457                             if (!t1.equals(t2)) {
458                                 match = false;
459                             }
460                         }
461 
462                         if (match) {
463                             method = curMethod;
464                             methodParameterTypes = curParameterTypes;
465 
466                             break;
467                         }
468                     }
469                     else if (method != null) {
470                         _log.error(
471                             "Obscure method name for class " + classObj +
472                                 ", method " + methodName + ", and parameters " +
473                                     parameterNames);
474 
475                         return null;
476                     }
477                     else {
478                         method = curMethod;
479                         methodParameterTypes = curParameterTypes;
480                     }
481                 }
482             }
483         }
484 
485         if (method != null) {
486             methodAndParameterTypes =
487                 new Object[] {method, methodParameterTypes};
488 
489             _methodCache.put(key, methodAndParameterTypes);
490 
491             return methodAndParameterTypes;
492         }
493         else {
494             _log.error(
495                 "No method found for class " + classObj + ", method " +
496                     methodName + ", and parameters " + parameterNames);
497 
498             return null;
499         }
500     }
501 
502     protected String getReturnValue(Object returnObj) throws Exception {
503         if ((returnObj instanceof Boolean) || (returnObj instanceof Double) ||
504             (returnObj instanceof Integer) || (returnObj instanceof Long) ||
505             (returnObj instanceof Short) || (returnObj instanceof String)) {
506 
507             JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
508 
509             jsonObj.put("returnValue", returnObj.toString());
510 
511             return jsonObj.toString();
512         }
513         else if (returnObj instanceof BaseModel<?>) {
514             String serlializerClassName = getSerializerClassName(returnObj);
515 
516             MethodWrapper methodWrapper = new MethodWrapper(
517                 serlializerClassName, "toJSONObject", returnObj);
518 
519             JSONObject jsonObj = (JSONObject)MethodInvoker.invoke(
520                 methodWrapper, false);
521 
522             return jsonObj.toString();
523         }
524         else if (returnObj instanceof BaseModel<?>[]) {
525             JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
526 
527             BaseModel<?>[] returnArray = (BaseModel[])returnObj;
528 
529             if (returnArray.length > 0) {
530                 BaseModel<?> returnItem0 = returnArray[0];
531 
532                 String serializerClassName = getSerializerClassName(
533                     returnItem0);
534 
535                 MethodWrapper methodWrapper = new MethodWrapper(
536                     serializerClassName, "toJSONArray", returnObj);
537 
538                 jsonArray = (JSONArray)MethodInvoker.invoke(
539                     methodWrapper, false);
540             }
541 
542             return jsonArray.toString();
543         }
544         else if (returnObj instanceof BaseModel<?>[][]) {
545             JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
546 
547             BaseModel<?>[][] returnArray = (BaseModel<?>[][])returnObj;
548 
549             if ((returnArray.length > 0) &&
550                 (returnArray[0].length > 0)) {
551 
552                 BaseModel<?> returnItem0 = returnArray[0][0];
553 
554                 String serializerClassName = getSerializerClassName(
555                     returnItem0);
556 
557                 MethodWrapper methodWrapper = new MethodWrapper(
558                     serializerClassName, "toJSONArray", returnObj);
559 
560                 jsonArray = (JSONArray)MethodInvoker.invoke(
561                     methodWrapper, false);
562             }
563 
564             return jsonArray.toString();
565         }
566         else if (returnObj instanceof List<?>) {
567             JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
568 
569             List<Object> returnList = (List<Object>)returnObj;
570 
571             if (!returnList.isEmpty()) {
572                 Object returnItem0 = returnList.get(0);
573 
574                 String serlializerClassName = getSerializerClassName(
575                     returnItem0);
576 
577                 MethodWrapper methodWrapper = new MethodWrapper(
578                     serlializerClassName, "toJSONArray", returnObj);
579 
580                 jsonArray = (JSONArray)MethodInvoker.invoke(
581                     methodWrapper, false);
582             }
583 
584             return jsonArray.toString();
585         }
586         else if (returnObj instanceof JSONArray) {
587             JSONArray jsonArray = (JSONArray)returnObj;
588 
589             return jsonArray.toString();
590         }
591         else if (returnObj instanceof JSONObject) {
592             JSONObject jsonObj = (JSONObject)returnObj;
593 
594             return jsonObj.toString();
595         }
596         else if (returnObj instanceof TagsAssetDisplay) {
597             return getReturnValue((TagsAssetDisplay)returnObj);
598         }
599         else if (returnObj instanceof TagsAssetDisplay[]) {
600             return getReturnValue((TagsAssetDisplay[])returnObj);
601         }
602         else if (returnObj instanceof TagsAssetType) {
603             return getReturnValue((TagsAssetType)returnObj);
604         }
605         else if (returnObj instanceof TagsAssetType[]) {
606             return getReturnValue((TagsAssetType[])returnObj);
607         }
608         else {
609             return JSONFactoryUtil.serialize(returnObj);
610         }
611     }
612 
613     protected String getReturnValue(TagsAssetDisplay assetDisplay)
614         throws Exception {
615 
616         JSONObject jsonObj = toJSONObject(assetDisplay);
617 
618         return jsonObj.toString();
619     }
620 
621     protected String getReturnValue(TagsAssetDisplay[] assetDisplays)
622         throws Exception {
623 
624         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
625 
626         for (int i = 0; i < assetDisplays.length; i++) {
627             TagsAssetDisplay assetDisplay = assetDisplays[i];
628 
629             jsonArray.put(toJSONObject(assetDisplay));
630         }
631 
632         return jsonArray.toString();
633     }
634 
635     protected String getReturnValue(TagsAssetType assetType)
636         throws Exception {
637 
638         JSONObject jsonObj = toJSONObject(assetType);
639 
640         return jsonObj.toString();
641     }
642 
643     protected String getReturnValue(TagsAssetType[] assetTypes)
644         throws Exception {
645 
646         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
647 
648         for (int i = 0; i < assetTypes.length; i++) {
649             TagsAssetType assetType = assetTypes[i];
650 
651             jsonArray.put(toJSONObject(assetType));
652         }
653 
654         return jsonArray.toString();
655     }
656 
657     protected String getSerializerClassName(Object obj) {
658         String serlializerClassName = StringUtil.replace(
659             obj.getClass().getName(),
660             new String[] {".model.impl.", "Impl"},
661             new String[] {".service.http.", "JSONSerializer"});
662 
663         return serlializerClassName;
664     }
665 
666     protected String[] getStringArrayFromJSON(
667             HttpServletRequest request, String param)
668         throws JSONException {
669 
670         String json = ParamUtil.getString(request, param, "[]");
671 
672         JSONArray jsonArray = JSONFactoryUtil.createJSONArray(json);
673 
674         return ArrayUtil.toStringArray(jsonArray);
675     }
676 
677     protected boolean isValidRequest(HttpServletRequest request) {
678         String className = ParamUtil.getString(request, "serviceClassName");
679 
680         if (className.contains(".service.") &&
681             className.endsWith("ServiceUtil") &&
682             !className.endsWith("LocalServiceUtil")) {
683 
684             return true;
685         }
686         else {
687             return false;
688         }
689     }
690 
691     private static Log _log = LogFactoryUtil.getLog(JSONServiceAction.class);
692 
693     private Map<String, Object[]> _methodCache =
694         new HashMap<String, Object[]>();
695 
696 }