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