1   /**
2    * Copyright (c) 2000-2008 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.util.ParamUtil;
29  import com.liferay.portal.kernel.util.StringUtil;
30  import com.liferay.portal.kernel.util.Validator;
31  import com.liferay.portal.struts.JSONAction;
32  import com.liferay.portlet.tags.model.TagsAssetDisplay;
33  import com.liferay.portlet.tags.model.TagsAssetType;
34  
35  import java.lang.reflect.InvocationTargetException;
36  import java.lang.reflect.Method;
37  
38  import java.util.Date;
39  import java.util.HashMap;
40  import java.util.Map;
41  
42  import javax.servlet.http.HttpServletRequest;
43  import javax.servlet.http.HttpServletResponse;
44  
45  import org.apache.commons.logging.Log;
46  import org.apache.commons.logging.LogFactory;
47  import org.apache.struts.action.ActionForm;
48  import org.apache.struts.action.ActionMapping;
49  
50  /**
51   * <a href="JSONServiceAction.java.html"><b><i>View Source</i></b></a>
52   *
53   * @author Brian Wing Shun Chan
54   * @author Karthik Sudarshan
55   *
56   */
57  public class JSONServiceAction extends JSONAction {
58  
59      public static JSONObject toJSONObject(TagsAssetDisplay assetDisplay) {
60          JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
61  
62          jsonObj.put("assetId", assetDisplay.getAssetId());
63          jsonObj.put("companyId", assetDisplay.getCompanyId());
64          jsonObj.put("userId", assetDisplay.getUserId());
65          jsonObj.put("userName", assetDisplay.getUserName());
66          jsonObj.put("createDate", assetDisplay.getCreateDate());
67          jsonObj.put("modifiedDate", assetDisplay.getModifiedDate());
68          jsonObj.put("classNameId", assetDisplay.getClassNameId());
69          jsonObj.put("className", assetDisplay.getClassName());
70          jsonObj.put("classPK", assetDisplay.getClassPK());
71          jsonObj.put("portletId", assetDisplay.getPortletId());
72          jsonObj.put("portletTitle", assetDisplay.getPortletTitle());
73          jsonObj.put("startDate", assetDisplay.getStartDate());
74          jsonObj.put("endDate", assetDisplay.getEndDate());
75          jsonObj.put("publishDate", assetDisplay.getPublishDate());
76          jsonObj.put("expirationDate", assetDisplay.getExpirationDate());
77          jsonObj.put("mimeType", assetDisplay.getMimeType());
78          jsonObj.put("title", assetDisplay.getTitle());
79          jsonObj.put("description", assetDisplay.getDescription());
80          jsonObj.put("summary", assetDisplay.getSummary());
81          jsonObj.put("url", assetDisplay.getUrl());
82          jsonObj.put("height", assetDisplay.getHeight());
83          jsonObj.put("width", assetDisplay.getWidth());
84          jsonObj.put("priority", assetDisplay.getPriority());
85          jsonObj.put("viewCount", assetDisplay.getViewCount());
86          jsonObj.put("tagsEntries", assetDisplay.getTagsEntries());
87  
88          return jsonObj;
89      }
90  
91      public static JSONObject toJSONObject(TagsAssetType assetType) {
92          JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
93  
94          jsonObj.put("classNameId", assetType.getClassNameId());
95          jsonObj.put("className", assetType.getClassName());
96          jsonObj.put("portletId", assetType.getPortletId());
97          jsonObj.put("portletTitle", assetType.getPortletTitle());
98  
99          return jsonObj;
100     }
101 
102     public String getJSON(
103             ActionMapping mapping, ActionForm form, HttpServletRequest request,
104             HttpServletResponse response)
105         throws Exception {
106 
107         String className = ParamUtil.getString(request, "serviceClassName");
108         String methodName = ParamUtil.getString(request, "serviceMethodName");
109         String[] serviceParameters = StringUtil.split(
110             ParamUtil.getString(request, "serviceParameters"));
111         String[] serviceParameterTypes = StringUtil.split(
112             ParamUtil.getString(request, "serviceParameterTypes"));
113 
114         if (!isValidRequest(request)) {
115             return null;
116         }
117 
118         Class<?> classObj = Class.forName(className);
119 
120         Object[] methodAndParameterTypes = getMethodAndParameterTypes(
121             classObj, methodName, serviceParameters, serviceParameterTypes);
122 
123         if (methodAndParameterTypes != null) {
124             Method method = (Method)methodAndParameterTypes[0];
125             Class<?>[] parameterTypes = (Class[])methodAndParameterTypes[1];
126             Object[] args = new Object[serviceParameters.length];
127 
128             for (int i = 0; i < serviceParameters.length; i++) {
129                 args[i] = getArgValue(
130                     request, classObj, methodName, serviceParameters[i],
131                     parameterTypes[i]);
132 
133             }
134 
135             try {
136                 if (_log.isDebugEnabled()) {
137                     _log.debug(
138                         "Invoking class " + classObj + " on method " +
139                             method.getName() + " with args " + args);
140                 }
141 
142                 Object returnObj = method.invoke(classObj, args);
143 
144                 if (returnObj != null) {
145                     if (returnObj instanceof JSONArray) {
146                         JSONArray jsonArray = (JSONArray)returnObj;
147 
148                         return jsonArray.toString();
149                     }
150                     else if (returnObj instanceof JSONObject) {
151                         JSONObject jsonObj = (JSONObject)returnObj;
152 
153                         return jsonObj.toString();
154                     }
155                     else if (returnObj instanceof Boolean ||
156                              returnObj instanceof Double ||
157                              returnObj instanceof Integer ||
158                              returnObj instanceof Long ||
159                              returnObj instanceof Short ||
160                              returnObj instanceof String) {
161 
162                         JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
163 
164                         jsonObj.put("returnValue", returnObj.toString());
165 
166                         return jsonObj.toString();
167                     }
168                     else {
169                         String returnValue = getReturnValue(returnObj);
170 
171                         if (returnValue == null) {
172                             _log.error(
173                                 "Unsupported return type for class " +
174                                     classObj + " and method " + methodName);
175                         }
176 
177                         return returnValue;
178                     }
179                 }
180                 else {
181                     JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
182 
183                     return jsonObj.toString();
184                 }
185             }
186             catch (InvocationTargetException ite) {
187                 JSONObject jsonObj = JSONFactoryUtil.createJSONObject();
188 
189                 jsonObj.put("exception", ite.getCause().toString());
190 
191                 return jsonObj.toString();
192             }
193         }
194 
195         return null;
196     }
197 
198     protected Object getArgValue(
199             HttpServletRequest request, Class<?> classObj, String methodName,
200             String parameter, Class<?> parameterType)
201         throws Exception {
202 
203         String parameterTypeName = parameterType.getName();
204 
205         if (parameterTypeName.equals("boolean") ||
206             parameterTypeName.equals(Boolean.class.getName())) {
207 
208             return Boolean.valueOf(ParamUtil.getBoolean(request, parameter));
209         }
210         else if (parameterTypeName.equals("double") ||
211                  parameterTypeName.equals(Double.class.getName())) {
212 
213             return new Double(ParamUtil.getDouble(request, parameter));
214         }
215         else if (parameterTypeName.equals("int") ||
216                  parameterTypeName.equals(Integer.class.getName())) {
217 
218             return new Integer(ParamUtil.getInteger(request, parameter));
219         }
220         else if (parameterTypeName.equals("long") ||
221                  parameterTypeName.equals(Long.class.getName())) {
222 
223             return new Long(ParamUtil.getLong(request, parameter));
224         }
225         else if (parameterTypeName.equals("short") ||
226                  parameterTypeName.equals(Short.class.getName())) {
227 
228             return new Short(ParamUtil.getShort(request, parameter));
229         }
230         else if (parameterTypeName.equals(Date.class.getName())) {
231             return new Date(ParamUtil.getLong(request, parameter));
232         }
233         else if (parameterTypeName.equals(String.class.getName())) {
234             String value = ParamUtil.getString(request, parameter);
235 
236             if (Validator.isNull(value)) {
237                 return null;
238             }
239             else {
240                 return value;
241             }
242         }
243         else if (parameterTypeName.equals("[Ljava.lang.String;")) {
244             return StringUtil.split(ParamUtil.getString(request, parameter));
245         }
246         else {
247             _log.error(
248                 "Unsupported parameter type for class " + classObj +
249                     ", method " + methodName + ", parameter " + parameter +
250                         ", and type " + parameterTypeName);
251 
252             return null;
253         }
254     }
255 
256     protected Object[] getMethodAndParameterTypes(
257             Class<?> classObj, String methodName, String[] parameters,
258             String[] parameterTypes)
259         throws Exception {
260 
261         String parameterNames = StringUtil.merge(parameters);
262 
263         String key =
264             classObj.getName() + "_METHOD_NAME_" + methodName +
265                 "_PARAMETERS_" + parameterNames;
266 
267         Object[] methodAndParameterTypes = _methodCache.get(key);
268 
269         if (methodAndParameterTypes != null) {
270             return methodAndParameterTypes;
271         }
272 
273         Method method = null;
274         Class<?>[] methodParameterTypes = null;
275 
276         Method[] methods = classObj.getMethods();
277 
278         for (int i = 0; i < methods.length; i++) {
279             Method curMethod = methods[i];
280 
281             if (curMethod.getName().equals(methodName)) {
282                 Class<?>[] curParameterTypes = curMethod.getParameterTypes();
283 
284                 if (curParameterTypes.length == parameters.length) {
285                     if ((parameterTypes.length > 0) &&
286                         (parameterTypes.length == curParameterTypes.length)) {
287 
288                         boolean match = true;
289 
290                         for (int j = 0; j < parameterTypes.length; j++) {
291                             String t1 = parameterTypes[j];
292                             String t2 = curParameterTypes[j].getName();
293 
294                             if (!t1.equals(t2)) {
295                                 match = false;
296                             }
297                         }
298 
299                         if (match) {
300                             method = curMethod;
301                             methodParameterTypes = curParameterTypes;
302 
303                             break;
304                         }
305                     }
306                     else if (method != null) {
307                         _log.error(
308                             "Obscure method name for class " + classObj +
309                                 ", method " + methodName + ", and parameters " +
310                                     parameterNames);
311 
312                         return null;
313                     }
314                     else {
315                         method = curMethod;
316                         methodParameterTypes = curParameterTypes;
317                     }
318                 }
319             }
320         }
321 
322         if (method != null) {
323             methodAndParameterTypes =
324                 new Object[] {method, methodParameterTypes};
325 
326             _methodCache.put(key, methodAndParameterTypes);
327 
328             return methodAndParameterTypes;
329         }
330         else {
331             _log.error(
332                 "No method found for class " + classObj + ", method " +
333                     methodName + ", and parameters " + parameterNames);
334 
335             return null;
336         }
337     }
338 
339     protected String getReturnValue(Object returnObj) throws Exception {
340         if (returnObj instanceof TagsAssetDisplay) {
341             return getReturnValue((TagsAssetDisplay)returnObj);
342         }
343         else if (returnObj instanceof TagsAssetDisplay[]) {
344             return getReturnValue((TagsAssetDisplay[])returnObj);
345         }
346         else if (returnObj instanceof TagsAssetType) {
347             return getReturnValue((TagsAssetType)returnObj);
348         }
349         else if (returnObj instanceof TagsAssetType[]) {
350             return getReturnValue((TagsAssetType[])returnObj);
351         }
352 
353         return null;
354     }
355 
356     protected String getReturnValue(TagsAssetDisplay assetDisplay)
357         throws Exception {
358 
359         JSONObject jsonObj = toJSONObject(assetDisplay);
360 
361         return jsonObj.toString();
362     }
363 
364     protected String getReturnValue(TagsAssetDisplay[] assetDisplays)
365         throws Exception {
366 
367         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
368 
369         for (int i = 0; i < assetDisplays.length; i++) {
370             TagsAssetDisplay assetDisplay = assetDisplays[i];
371 
372             jsonArray.put(toJSONObject(assetDisplay));
373         }
374 
375         return jsonArray.toString();
376     }
377 
378     protected String getReturnValue(TagsAssetType assetType)
379         throws Exception {
380 
381         JSONObject jsonObj = toJSONObject(assetType);
382 
383         return jsonObj.toString();
384     }
385 
386     protected String getReturnValue(TagsAssetType[] assetTypes)
387         throws Exception {
388 
389         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
390 
391         for (int i = 0; i < assetTypes.length; i++) {
392             TagsAssetType assetType = assetTypes[i];
393 
394             jsonArray.put(toJSONObject(assetType));
395         }
396 
397         return jsonArray.toString();
398     }
399 
400     protected boolean isValidRequest(HttpServletRequest request) {
401         String className = ParamUtil.getString(request, "serviceClassName");
402 
403         if (className.contains(".service.http.") &&
404             className.endsWith("ServiceJSON")) {
405 
406             return true;
407         }
408         else {
409             return false;
410         }
411     }
412 
413     private static Log _log = LogFactory.getLog(JSONServiceAction.class);
414 
415     private Map<String, Object[]> _methodCache =
416         new HashMap<String, Object[]>();
417 
418 }