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