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