1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.action;
24  
25  import com.liferay.portal.kernel.json.JSONArray;
26  import com.liferay.portal.kernel.json.JSONFactoryUtil;
27  import com.liferay.portal.kernel.json.JSONObject;
28  import com.liferay.portal.kernel.log.Log;
29  import com.liferay.portal.kernel.log.LogFactoryUtil;
30  import com.liferay.portal.kernel.util.ParamUtil;
31  import com.liferay.portal.kernel.util.StringUtil;
32  import com.liferay.portal.kernel.util.Validator;
33  import com.liferay.portal.service.ServiceContext;
34  import com.liferay.portal.service.ServiceContextUtil;
35  import com.liferay.portal.struts.JSONAction;
36  import com.liferay.portlet.tags.model.TagsAssetDisplay;
37  import com.liferay.portlet.tags.model.TagsAssetType;
38  
39  import java.lang.reflect.InvocationTargetException;
40  import java.lang.reflect.Method;
41  
42  import java.util.Date;
43  import java.util.HashMap;
44  import java.util.Map;
45  
46  import javax.servlet.http.HttpServletRequest;
47  import javax.servlet.http.HttpServletResponse;
48  
49  import org.apache.struts.action.ActionForm;
50  import org.apache.struts.action.ActionMapping;
51  
52  /**
53   * <a href="JSONServiceAction.java.html"><b><i>View Source</i></b></a>
54   *
55   * @author Brian Wing Shun Chan
56   * @author Karthik Sudarshan
57   *
58   */
59  public class JSONServiceAction extends JSONAction {
60  
61      public static JSONObject toJSONObject(TagsAssetDisplay assetDisplay) {
62          JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
63  
64          jsonObj.put("assetId", assetDisplay.getAssetId());
65          jsonObj.put("companyId", assetDisplay.getCompanyId());
66          jsonObj.put("userId", assetDisplay.getUserId());
67          jsonObj.put("userName", assetDisplay.getUserName());
68          jsonObj.put("createDate", assetDisplay.getCreateDate());
69          jsonObj.put("modifiedDate", assetDisplay.getModifiedDate());
70          jsonObj.put("classNameId", assetDisplay.getClassNameId());
71          jsonObj.put("className", assetDisplay.getClassName());
72          jsonObj.put("classPK", assetDisplay.getClassPK());
73          jsonObj.put("portletId", assetDisplay.getPortletId());
74          jsonObj.put("portletTitle", assetDisplay.getPortletTitle());
75          jsonObj.put("startDate", assetDisplay.getStartDate());
76          jsonObj.put("endDate", assetDisplay.getEndDate());
77          jsonObj.put("publishDate", assetDisplay.getPublishDate());
78          jsonObj.put("expirationDate", assetDisplay.getExpirationDate());
79          jsonObj.put("mimeType", assetDisplay.getMimeType());
80          jsonObj.put("title", assetDisplay.getTitle());
81          jsonObj.put("description", assetDisplay.getDescription());
82          jsonObj.put("summary", assetDisplay.getSummary());
83          jsonObj.put("url", assetDisplay.getUrl());
84          jsonObj.put("height", assetDisplay.getHeight());
85          jsonObj.put("width", assetDisplay.getWidth());
86          jsonObj.put("priority", assetDisplay.getPriority());
87          jsonObj.put("viewCount", assetDisplay.getViewCount());
88          jsonObj.put("tagsEntries", assetDisplay.getTagsEntries());
89  
90          return jsonObj;
91      }
92  
93      public static JSONObject toJSONObject(TagsAssetType assetType) {
94          JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
95  
96          jsonObj.put("classNameId", assetType.getClassNameId());
97          jsonObj.put("className", assetType.getClassName());
98          jsonObj.put("portletId", assetType.getPortletId());
99          jsonObj.put("portletTitle", assetType.getPortletTitle());
100 
101         return jsonObj;
102     }
103 
104     public String getJSON(
105             ActionMapping mapping, ActionForm form, HttpServletRequest request,
106             HttpServletResponse response)
107         throws Exception {
108 
109         String className = ParamUtil.getString(request, "serviceClassName");
110         String methodName = ParamUtil.getString(request, "serviceMethodName");
111         String[] serviceParameters = StringUtil.split(
112             ParamUtil.getString(request, "serviceParameters"));
113         String[] serviceParameterTypes = StringUtil.split(
114             ParamUtil.getString(request, "serviceParameterTypes"));
115 
116         if (!isValidRequest(request)) {
117             return null;
118         }
119 
120         Class<?> classObj = Class.forName(className);
121 
122         Object[] methodAndParameterTypes = getMethodAndParameterTypes(
123             classObj, methodName, serviceParameters, serviceParameterTypes);
124 
125         if (methodAndParameterTypes != null) {
126             Method method = (Method)methodAndParameterTypes[0];
127             Class<?>[] parameterTypes = (Class[])methodAndParameterTypes[1];
128             Object[] args = new Object[serviceParameters.length];
129 
130             for (int i = 0; i < serviceParameters.length; i++) {
131                 args[i] = getArgValue(
132                     request, classObj, methodName, serviceParameters[i],
133                     parameterTypes[i]);
134             }
135 
136             try {
137                 if (_log.isDebugEnabled()) {
138                     _log.debug(
139                         "Invoking class " + classObj + " on method " +
140                             method.getName() + " with args " + args);
141                 }
142 
143                 Object returnObj = method.invoke(classObj, args);
144 
145                 if (returnObj != null) {
146                     if (returnObj instanceof JSONArray) {
147                         JSONArray jsonArray = (JSONArray)returnObj;
148 
149                         return jsonArray.toString();
150                     }
151                     else if (returnObj instanceof JSONObject) {
152                         JSONObject jsonObj = (JSONObject)returnObj;
153 
154                         return jsonObj.toString();
155                     }
156                     else if (returnObj instanceof Boolean ||
157                              returnObj instanceof Double ||
158                              returnObj instanceof Integer ||
159                              returnObj instanceof Long ||
160                              returnObj instanceof Short ||
161                              returnObj instanceof String) {
162 
163                         JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
164 
165                         jsonObj.put("returnValue", returnObj.toString());
166 
167                         return jsonObj.toString();
168                     }
169                     else {
170                         String returnValue = getReturnValue(returnObj);
171 
172                         if (returnValue == null) {
173                             _log.error(
174                                 "Unsupported return type for class " +
175                                     classObj + " and method " + methodName);
176                         }
177 
178                         return returnValue;
179                     }
180                 }
181                 else {
182                     JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
183 
184                     return jsonObj.toString();
185                 }
186             }
187             catch (InvocationTargetException ite) {
188                 JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
189 
190                 jsonObj.put("exception", ite.getCause().toString());
191 
192                 return jsonObj.toString();
193             }
194         }
195 
196         return null;
197     }
198 
199     protected Object getArgValue(
200             HttpServletRequest request, Class<?> classObj, String methodName,
201             String parameter, Class<?> parameterType)
202         throws Exception {
203 
204         String parameterTypeName = parameterType.getName();
205 
206         String value = ParamUtil.getString(request, parameter);
207 
208         if (Validator.isNull(value) &&
209             !parameterTypeName.equals("[Ljava.lang.String;")) {
210 
211             return null;
212         }
213         else if (parameterTypeName.equals("boolean") ||
214                  parameterTypeName.equals(Boolean.class.getName())) {
215 
216             return Boolean.valueOf(ParamUtil.getBoolean(request, parameter));
217         }
218         else if (parameterTypeName.equals("double") ||
219                  parameterTypeName.equals(Double.class.getName())) {
220 
221             return new Double(ParamUtil.getDouble(request, parameter));
222         }
223         else if (parameterTypeName.equals("int") ||
224                  parameterTypeName.equals(Integer.class.getName())) {
225 
226             return new Integer(ParamUtil.getInteger(request, parameter));
227         }
228         else if (parameterTypeName.equals("long") ||
229                  parameterTypeName.equals(Long.class.getName())) {
230 
231             return new Long(ParamUtil.getLong(request, parameter));
232         }
233         else if (parameterTypeName.equals("short") ||
234                  parameterTypeName.equals(Short.class.getName())) {
235 
236             return new Short(ParamUtil.getShort(request, parameter));
237         }
238         else if (parameterTypeName.equals(Date.class.getName())) {
239             return new Date(ParamUtil.getLong(request, parameter));
240         }
241         else if (parameterTypeName.equals(ServiceContext.class.getName())) {
242             JSONObject jsonObject = JSONFactoryUtil.createJSONObject(value);
243 
244             jsonObject.put("javaClass", ServiceContext.class.getName());
245 
246             return ServiceContextUtil.deserialize(jsonObject);
247         }
248         else if (parameterTypeName.equals(String.class.getName())) {
249             return value;
250         }
251         else if (parameterTypeName.equals("[Ljava.lang.String;")) {
252             return StringUtil.split(value);
253         }
254         else {
255             _log.error(
256                 "Unsupported parameter type for class " + classObj +
257                     ", method " + methodName + ", parameter " + parameter +
258                         ", and type " + parameterTypeName);
259 
260             return null;
261         }
262     }
263 
264     protected Object[] getMethodAndParameterTypes(
265             Class<?> classObj, String methodName, String[] parameters,
266             String[] parameterTypes)
267         throws Exception {
268 
269         String parameterNames = StringUtil.merge(parameters);
270 
271         String key =
272             classObj.getName() + "_METHOD_NAME_" + methodName +
273                 "_PARAMETERS_" + parameterNames;
274 
275         Object[] methodAndParameterTypes = _methodCache.get(key);
276 
277         if (methodAndParameterTypes != null) {
278             return methodAndParameterTypes;
279         }
280 
281         Method method = null;
282         Class<?>[] methodParameterTypes = null;
283 
284         Method[] methods = classObj.getMethods();
285 
286         for (int i = 0; i < methods.length; i++) {
287             Method curMethod = methods[i];
288 
289             if (curMethod.getName().equals(methodName)) {
290                 Class<?>[] curParameterTypes = curMethod.getParameterTypes();
291 
292                 if (curParameterTypes.length == parameters.length) {
293                     if ((parameterTypes.length > 0) &&
294                         (parameterTypes.length == curParameterTypes.length)) {
295 
296                         boolean match = true;
297 
298                         for (int j = 0; j < parameterTypes.length; j++) {
299                             String t1 = parameterTypes[j];
300                             String t2 = curParameterTypes[j].getName();
301 
302                             if (!t1.equals(t2)) {
303                                 match = false;
304                             }
305                         }
306 
307                         if (match) {
308                             method = curMethod;
309                             methodParameterTypes = curParameterTypes;
310 
311                             break;
312                         }
313                     }
314                     else if (method != null) {
315                         _log.error(
316                             "Obscure method name for class " + classObj +
317                                 ", method " + methodName + ", and parameters " +
318                                     parameterNames);
319 
320                         return null;
321                     }
322                     else {
323                         method = curMethod;
324                         methodParameterTypes = curParameterTypes;
325                     }
326                 }
327             }
328         }
329 
330         if (method != null) {
331             methodAndParameterTypes =
332                 new Object[] {method, methodParameterTypes};
333 
334             _methodCache.put(key, methodAndParameterTypes);
335 
336             return methodAndParameterTypes;
337         }
338         else {
339             _log.error(
340                 "No method found for class " + classObj + ", method " +
341                     methodName + ", and parameters " + parameterNames);
342 
343             return null;
344         }
345     }
346 
347     protected String getReturnValue(Object returnObj) throws Exception {
348         if (returnObj instanceof TagsAssetDisplay) {
349             return getReturnValue((TagsAssetDisplay)returnObj);
350         }
351         else if (returnObj instanceof TagsAssetDisplay[]) {
352             return getReturnValue((TagsAssetDisplay[])returnObj);
353         }
354         else if (returnObj instanceof TagsAssetType) {
355             return getReturnValue((TagsAssetType)returnObj);
356         }
357         else if (returnObj instanceof TagsAssetType[]) {
358             return getReturnValue((TagsAssetType[])returnObj);
359         }
360 
361         return null;
362     }
363 
364     protected String getReturnValue(TagsAssetDisplay assetDisplay)
365         throws Exception {
366 
367         JSONObject jsonObj = toJSONObject(assetDisplay);
368 
369         return jsonObj.toString();
370     }
371 
372     protected String getReturnValue(TagsAssetDisplay[] assetDisplays)
373         throws Exception {
374 
375         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
376 
377         for (int i = 0; i < assetDisplays.length; i++) {
378             TagsAssetDisplay assetDisplay = assetDisplays[i];
379 
380             jsonArray.put(toJSONObject(assetDisplay));
381         }
382 
383         return jsonArray.toString();
384     }
385 
386     protected String getReturnValue(TagsAssetType assetType)
387         throws Exception {
388 
389         JSONObject jsonObj = toJSONObject(assetType);
390 
391         return jsonObj.toString();
392     }
393 
394     protected String getReturnValue(TagsAssetType[] assetTypes)
395         throws Exception {
396 
397         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
398 
399         for (int i = 0; i < assetTypes.length; i++) {
400             TagsAssetType assetType = assetTypes[i];
401 
402             jsonArray.put(toJSONObject(assetType));
403         }
404 
405         return jsonArray.toString();
406     }
407 
408     protected boolean isValidRequest(HttpServletRequest request) {
409         String className = ParamUtil.getString(request, "serviceClassName");
410 
411         if (className.contains(".service.http.") &&
412             className.endsWith("ServiceJSON")) {
413 
414             return true;
415         }
416         else {
417             return false;
418         }
419     }
420 
421     private static Log _log = LogFactoryUtil.getLog(JSONServiceAction.class);
422 
423     private Map<String, Object[]> _methodCache =
424         new HashMap<String, Object[]>();
425 
426 }