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