001
014
015 package com.liferay.portal.jsonwebservice;
016
017 import com.liferay.portal.kernel.json.JSONFactoryUtil;
018 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceAction;
019 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionMapping;
020 import com.liferay.portal.kernel.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.util.CamelCaseUtil;
023 import com.liferay.portal.kernel.util.GetterUtil;
024 import com.liferay.portal.kernel.util.LocaleUtil;
025 import com.liferay.portal.kernel.util.MethodParameter;
026 import com.liferay.portal.kernel.util.StringPool;
027 import com.liferay.portal.service.ServiceContext;
028
029 import java.lang.reflect.Array;
030 import java.lang.reflect.Method;
031
032 import java.util.ArrayList;
033 import java.util.Calendar;
034 import java.util.Collection;
035 import java.util.HashMap;
036 import java.util.List;
037 import java.util.Locale;
038 import java.util.Map;
039
040 import jodd.bean.BeanCopy;
041 import jodd.bean.BeanUtil;
042
043 import jodd.typeconverter.TypeConverterManager;
044
045 import jodd.util.NameValue;
046 import jodd.util.ReflectUtil;
047
048
051 public class JSONWebServiceActionImpl implements JSONWebServiceAction {
052
053 public JSONWebServiceActionImpl(
054 JSONWebServiceActionConfig jsonWebServiceActionConfig,
055 JSONWebServiceActionParameters jsonWebServiceActionParameters) {
056
057 _jsonWebServiceActionConfig = jsonWebServiceActionConfig;
058 _jsonWebServiceActionParameters = jsonWebServiceActionParameters;
059 }
060
061 @Override
062 public JSONWebServiceActionMapping getJSONWebServiceActionMapping() {
063 return _jsonWebServiceActionConfig;
064 }
065
066 @Override
067 public Object invoke() throws Exception {
068 JSONRPCRequest jsonRPCRequest =
069 _jsonWebServiceActionParameters.getJSONRPCRequest();
070
071 if (jsonRPCRequest == null) {
072 return _invokeActionMethod();
073 }
074
075 Object result = null;
076 Exception exception = null;
077
078 try {
079 result = _invokeActionMethod();
080 }
081 catch (Exception e) {
082 exception = e;
083
084 _log.error(e, e);
085 }
086
087 return new JSONRPCResponse(jsonRPCRequest, result, exception);
088 }
089
090 private Object _convertListToArray(List<?> list, Class<?> componentType) {
091 Object array = Array.newInstance(componentType, list.size());
092
093 for (int i = 0; i < list.size(); i++) {
094 Object entry = list.get(i);
095
096 if (entry != null) {
097 entry = TypeConverterManager.convertType(entry, componentType);
098 }
099
100 Array.set(array, i, entry);
101 }
102
103 return array;
104 }
105
106 private Object _convertValueToParameterValue(
107 Object value, Class<?> parameterType,
108 Class<?>[] genericParameterTypes) {
109
110 if (parameterType.isArray()) {
111 List<?> list = null;
112
113 if (value instanceof List) {
114 list = (List<?>)value;
115 }
116 else {
117 String valueString = value.toString();
118
119 valueString = valueString.trim();
120
121 if (!valueString.startsWith(StringPool.OPEN_BRACKET)) {
122 valueString = StringPool.OPEN_BRACKET.concat(
123 valueString).concat(StringPool.CLOSE_BRACKET);
124 }
125
126 list = JSONFactoryUtil.looseDeserializeSafe(
127 valueString, ArrayList.class);
128 }
129
130 return _convertListToArray(list, parameterType.getComponentType());
131 }
132 else if (parameterType.equals(Calendar.class)) {
133 Calendar calendar = Calendar.getInstance();
134
135 calendar.setLenient(false);
136
137 String valueString = value.toString();
138
139 valueString = valueString.trim();
140
141 long timeInMillis = GetterUtil.getLong(valueString);
142
143 calendar.setTimeInMillis(timeInMillis);
144
145 return calendar;
146 }
147 else if (Collection.class.isAssignableFrom(parameterType)) {
148 List<?> list = null;
149
150 if (value instanceof List) {
151 list = (List<?>)value;
152 }
153 else {
154 String valueString = value.toString();
155
156 valueString = valueString.trim();
157
158 if (!valueString.startsWith(StringPool.OPEN_BRACKET)) {
159 valueString = StringPool.OPEN_BRACKET.concat(
160 valueString).concat(StringPool.CLOSE_BRACKET);
161 }
162
163 list = JSONFactoryUtil.looseDeserializeSafe(
164 valueString, ArrayList.class);
165 }
166
167 return _generifyList(list, genericParameterTypes);
168 }
169 else if (parameterType.equals(Locale.class)) {
170 String valueString = value.toString();
171
172 valueString = valueString.trim();
173
174 return LocaleUtil.fromLanguageId(valueString);
175 }
176 else if (parameterType.equals(Map.class)) {
177 Map<?, ?> map = null;
178
179 if (value instanceof Map) {
180 map = (Map<Object, Object>)value;
181 }
182 else {
183 String valueString = value.toString();
184
185 valueString = valueString.trim();
186
187 map = JSONFactoryUtil.looseDeserializeSafe(
188 valueString, HashMap.class);
189 }
190
191 return _generifyMap(map, genericParameterTypes);
192 }
193 else {
194 Object parameterValue = null;
195
196 try {
197 parameterValue = TypeConverterManager.convertType(
198 value, parameterType);
199 }
200 catch (Exception e1) {
201 if (value instanceof Map) {
202 try {
203 parameterValue = _createDefaultParameterValue(
204 null, parameterType);
205 }
206 catch (Exception e2) {
207 throw new ClassCastException(e1.getMessage());
208 }
209
210 BeanCopy beanCopy = BeanCopy.beans(value, parameterValue);
211
212 beanCopy.copy();
213 }
214 else {
215 String valueString = value.toString();
216
217 valueString = valueString.trim();
218
219 if (!valueString.startsWith(StringPool.OPEN_CURLY_BRACE)) {
220 throw new ClassCastException(e1.getMessage());
221 }
222
223 parameterValue = JSONFactoryUtil.looseDeserializeSafe(
224 valueString, parameterType);
225 }
226 }
227
228 return parameterValue;
229 }
230 }
231
232 private Object _createDefaultParameterValue(
233 String parameterName, Class<?> parameterType)
234 throws Exception {
235
236 if ((parameterName != null) && parameterName.equals("serviceContext") &&
237 parameterType.equals(ServiceContext.class)) {
238
239 return new ServiceContext();
240 }
241
242 String className = parameterType.getName();
243
244 if (className.contains("com.liferay") && className.contains("Util")) {
245 throw new IllegalArgumentException(
246 "Not instantiating " + className);
247 }
248
249 return parameterType.newInstance();
250 }
251
252 private List<?> _generifyList(List<?> list, Class<?>[] types) {
253 if (types == null) {
254 return list;
255 }
256
257 if (types.length != 1) {
258 return list;
259 }
260
261 List<Object> newList = new ArrayList<Object>(list.size());
262
263 for (Object entry : list) {
264 if (entry != null) {
265 entry = TypeConverterManager.convertType(entry, types[0]);
266 }
267
268 newList.add(entry);
269 }
270
271 return newList;
272 }
273
274 private Map<?, ?> _generifyMap(Map<?, ?> map, Class<?>[] types) {
275 if (types == null) {
276 return map;
277 }
278
279 if (types.length != 2) {
280 return map;
281 }
282
283 Map<Object, Object> newMap = new HashMap<Object, Object>(map.size());
284
285 for (Map.Entry<?, ?> entry : map.entrySet()) {
286 Object key = TypeConverterManager.convertType(
287 entry.getKey(), types[0]);
288
289 Object value = entry.getValue();
290
291 if (value != null) {
292 value = TypeConverterManager.convertType(value, types[1]);
293 }
294
295 newMap.put(key, value);
296 }
297
298 return newMap;
299 }
300
301 private void _injectInnerParametersIntoValue(
302 String parameterName, Object parameterValue) {
303
304 if (parameterValue == null) {
305 return;
306 }
307
308 List<NameValue<String, Object>> innerParameters =
309 _jsonWebServiceActionParameters.getInnerParameters(parameterName);
310
311 if (innerParameters == null) {
312 return;
313 }
314
315 for (NameValue<String, Object> innerParameter : innerParameters) {
316 try {
317 BeanUtil.setProperty(
318 parameterValue, innerParameter.getName(),
319 innerParameter.getValue());
320 }
321 catch (Exception e) {
322 if (_log.isDebugEnabled()) {
323 _log.debug(
324 "Unable to set inner parameter " + parameterName + "." +
325 innerParameter.getName(),
326 e);
327 }
328 }
329 }
330 }
331
332 private Object _invokeActionMethod() throws Exception {
333 Object actionObject = _jsonWebServiceActionConfig.getActionObject();
334
335 Method actionMethod = _jsonWebServiceActionConfig.getActionMethod();
336
337 Class<?> actionClass = _jsonWebServiceActionConfig.getActionClass();
338
339 Object[] parameters = _prepareParameters(actionClass);
340
341 return actionMethod.invoke(actionObject, parameters);
342 }
343
344 private Object[] _prepareParameters(Class<?> actionClass) throws Exception {
345 MethodParameter[] methodParameters =
346 _jsonWebServiceActionConfig.getMethodParameters();
347
348 Object[] parameters = new Object[methodParameters.length];
349
350 for (int i = 0; i < methodParameters.length; i++) {
351 String parameterName = methodParameters[i].getName();
352
353 parameterName = CamelCaseUtil.normalizeCamelCase(parameterName);
354
355 Object value = _jsonWebServiceActionParameters.getParameter(
356 parameterName);
357
358 Object parameterValue = null;
359
360 if (value != null) {
361 Class<?> parameterType = methodParameters[i].getType();
362
363 String parameterTypeName =
364 _jsonWebServiceActionParameters.getParameterTypeName(
365 parameterName);
366
367 if (parameterTypeName != null) {
368 ClassLoader classLoader = actionClass.getClassLoader();
369
370 parameterType = classLoader.loadClass(parameterTypeName);
371
372 if (!ReflectUtil.isSubclass(
373 parameterType, methodParameters[i].getType())) {
374
375 throw new IllegalArgumentException(
376 "Unmatched argument type " +
377 parameterType.getName() +
378 " for method argument " + i);
379 }
380 }
381
382 if (value.equals(Void.TYPE)) {
383 parameterValue = _createDefaultParameterValue(
384 parameterName, parameterType);
385 }
386 else {
387 parameterValue = _convertValueToParameterValue(
388 value, parameterType,
389 methodParameters[i].getGenericTypes());
390
391 ServiceContext serviceContext =
392 _jsonWebServiceActionParameters.getServiceContext();
393
394 if ((serviceContext != null) &&
395 parameterName.equals("serviceContext")) {
396
397 if ((parameterValue != null) &&
398 ServiceContext.class.isAssignableFrom(
399 parameterValue.getClass())) {
400
401 serviceContext.merge(
402 (ServiceContext)parameterValue);
403 }
404
405 parameterValue = serviceContext;
406 }
407 }
408 }
409
410 _injectInnerParametersIntoValue(parameterName, parameterValue);
411
412 parameters[i] = parameterValue;
413 }
414
415 return parameters;
416 }
417
418 private static Log _log = LogFactoryUtil.getLog(
419 JSONWebServiceActionImpl.class);
420
421 private JSONWebServiceActionConfig _jsonWebServiceActionConfig;
422 private JSONWebServiceActionParameters _jsonWebServiceActionParameters;
423
424 }