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