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