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