001
014
015 package com.liferay.portal.jsonwebservice.action;
016
017 import com.liferay.portal.json.data.FileData;
018 import com.liferay.portal.json.transformer.BeanAnalyzerTransformer;
019 import com.liferay.portal.kernel.exception.PortalException;
020 import com.liferay.portal.kernel.javadoc.JavadocManagerUtil;
021 import com.liferay.portal.kernel.javadoc.JavadocMethod;
022 import com.liferay.portal.kernel.json.JSONFactoryUtil;
023 import com.liferay.portal.kernel.json.JSONSerializable;
024 import com.liferay.portal.kernel.json.JSONSerializer;
025 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceAction;
026 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionMapping;
027 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionsManagerUtil;
028 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceNaming;
029 import com.liferay.portal.kernel.util.GetterUtil;
030 import com.liferay.portal.kernel.util.MethodParameter;
031 import com.liferay.portal.kernel.util.ParamUtil;
032 import com.liferay.portal.kernel.util.ReleaseInfo;
033 import com.liferay.portal.kernel.util.StringBundler;
034 import com.liferay.portal.kernel.util.StringPool;
035 import com.liferay.portal.kernel.util.StringUtil;
036 import com.liferay.portal.kernel.util.Validator;
037
038 import java.io.File;
039 import java.io.Serializable;
040
041 import java.lang.reflect.Method;
042 import java.lang.reflect.Modifier;
043 import java.lang.reflect.ParameterizedType;
044 import java.lang.reflect.Type;
045
046 import java.util.ArrayList;
047 import java.util.Collection;
048 import java.util.Date;
049 import java.util.HashMap;
050 import java.util.LinkedHashMap;
051 import java.util.List;
052 import java.util.Locale;
053 import java.util.Map;
054 import java.util.TimeZone;
055
056 import javax.servlet.ServletContext;
057 import javax.servlet.http.HttpServletRequest;
058
059 import jodd.util.ReflectUtil;
060
061
065 public class JSONWebServiceDiscoverAction implements JSONWebServiceAction {
066
067 public JSONWebServiceDiscoverAction(HttpServletRequest request) {
068 _basePath = request.getServletPath();
069 _baseURL = String.valueOf(request.getRequestURL());
070
071 ServletContext servletContext = request.getServletContext();
072
073 _contextName = GetterUtil.getString(
074 ParamUtil.getString(
075 request, "contextName", servletContext.getServletContextName()),
076 StringPool.BLANK);
077 _jsonWebServiceNaming =
078 JSONWebServiceActionsManagerUtil.getJSONWebServiceNaming();
079 }
080
081 @Override
082 public JSONWebServiceActionMapping getJSONWebServiceActionMapping() {
083 return null;
084 }
085
086 @Override
087 public Object invoke() throws Exception {
088 Map<String, Object> resultsMap = new LinkedHashMap<String, Object>();
089
090 resultsMap.put("contextName", _contextName);
091 resultsMap.put("basePath", _basePath);
092 resultsMap.put("baseURL", _baseURL);
093 resultsMap.put("services", _buildJsonWebServiceActionMappingMaps());
094 resultsMap.put("types", _buildTypes());
095 resultsMap.put("version", ReleaseInfo.getVersion());
096
097 return new DiscoveryContent(resultsMap);
098 }
099
100 public static class DiscoveryContent implements JSONSerializable {
101
102 public DiscoveryContent(Map<String, Object> resultsMap) {
103 _resultsMap = resultsMap;
104 }
105
106 @Override
107 public String toJSONString() {
108 JSONSerializer jsonSerializer =
109 JSONFactoryUtil.createJSONSerializer();
110
111 jsonSerializer.include("types");
112
113 return jsonSerializer.serializeDeep(_resultsMap);
114 }
115
116 private Map<String, Object> _resultsMap;
117
118 }
119
120 private List<Map<String, Object>> _buildJsonWebServiceActionMappingMaps()
121 throws PortalException {
122
123 List<JSONWebServiceActionMapping> jsonWebServiceActionMappings =
124 JSONWebServiceActionsManagerUtil.getJSONWebServiceActionMappings(
125 _contextName);
126
127 List<Map<String, Object>> jsonWebServiceActionMappingMaps =
128 new ArrayList<Map<String, Object>>(
129 jsonWebServiceActionMappings.size());
130
131 for (JSONWebServiceActionMapping jsonWebServiceActionMapping :
132 jsonWebServiceActionMappings) {
133
134 String path = jsonWebServiceActionMapping.getPath();
135
136 Map<String, Object> jsonWebServiceActionMappingMap =
137 new LinkedHashMap<String, Object>();
138
139 if (jsonWebServiceActionMapping.isDeprecated()) {
140 jsonWebServiceActionMappingMap.put("deprecated", Boolean.TRUE);
141 }
142
143 JavadocMethod javadocMethod =
144 JavadocManagerUtil.lookupJavadocMethod(
145 jsonWebServiceActionMapping.getRealActionMethod());
146
147 if (javadocMethod != null) {
148 String methodComment = javadocMethod.getComment();
149
150 if (methodComment != null) {
151 jsonWebServiceActionMappingMap.put(
152 "description", javadocMethod.getComment());
153 }
154 }
155
156 jsonWebServiceActionMappingMap.put(
157 "method", jsonWebServiceActionMapping.getMethod());
158
159 jsonWebServiceActionMappingMap.put(
160 "name", _getName(jsonWebServiceActionMapping));
161
162 MethodParameter[] methodParameters =
163 jsonWebServiceActionMapping.getMethodParameters();
164
165 List<Map<String, String>> parametersList =
166 new ArrayList<Map<String, String>>(methodParameters.length);
167
168 for (int i = 0; i < methodParameters.length; i++) {
169 MethodParameter methodParameter = methodParameters[i];
170
171 Class<?>[] genericTypes = null;
172
173 try {
174 genericTypes = methodParameter.getGenericTypes();
175 }
176 catch (ClassNotFoundException cnfe) {
177 throw new PortalException(cnfe);
178 }
179
180 Map<String, String> parameterMap =
181 new HashMap<String, String>();
182
183 if (javadocMethod != null) {
184 String parameterComment = javadocMethod.getParameterComment(
185 i);
186
187 if (!Validator.isBlank(parameterComment)) {
188 parameterMap.put("description", parameterComment);
189 }
190 }
191
192 parameterMap.put("name", methodParameter.getName());
193 parameterMap.put(
194 "type",
195 _formatType(
196 methodParameter.getType(), genericTypes, false));
197
198 parametersList.add(parameterMap);
199 }
200
201 jsonWebServiceActionMappingMap.put("parameters", parametersList);
202
203 jsonWebServiceActionMappingMap.put("path", path);
204
205 Map<String, String> returnsMap =
206 new LinkedHashMap<String, String>();
207
208 if (javadocMethod != null) {
209 String returnComment = javadocMethod.getReturnComment();
210
211 if (!Validator.isBlank(returnComment)) {
212 returnsMap.put("description", returnComment);
213 }
214 }
215
216 Method actionMethod = jsonWebServiceActionMapping.getActionMethod();
217
218 returnsMap.put(
219 "type",
220 _formatType(
221 actionMethod.getReturnType(),
222 _getGenericReturnTypes(jsonWebServiceActionMapping), true));
223
224 jsonWebServiceActionMappingMap.put("returns", returnsMap);
225
226 jsonWebServiceActionMappingMaps.add(jsonWebServiceActionMappingMap);
227 }
228
229 return jsonWebServiceActionMappingMaps;
230 }
231
232 private List<Map<String, String>> _buildPropertiesList(Class<?> type) {
233 try {
234 BeanAnalyzerTransformer beanAnalyzerTransformer =
235 new BeanAnalyzerTransformer(type) {
236
237 @Override
238 protected String getTypeName(Class<?> type) {
239 return _formatType(type, null, false);
240 }
241
242 };
243
244 return beanAnalyzerTransformer.collect();
245 }
246 catch (Exception e) {
247 return null;
248 }
249 }
250
251 private List<Map<String, Object>> _buildTypes() {
252 List<Map<String, Object>> types = new ArrayList<Map<String, Object>>();
253
254 for (int i = 0; i < _types.size(); i++) {
255 Class<?> type = _types.get(i);
256
257 Map<String, Object> map = new LinkedHashMap<String, Object>();
258
259 types.add(map);
260
261 Class<?> modelType = type;
262
263 if (type.isInterface()) {
264 try {
265 Class<?> clazz = getClass();
266
267 ClassLoader classLoader = clazz.getClassLoader();
268
269 String modelImplClassName =
270 _jsonWebServiceNaming.convertModelClassToImplClassName(
271 type);
272
273 modelType = classLoader.loadClass(modelImplClassName);
274 }
275 catch (ClassNotFoundException cnfe) {
276 }
277 }
278
279 if (modelType.isInterface() ||
280 Modifier.isAbstract(modelType.getModifiers())) {
281
282 map.put("interface", Boolean.TRUE);
283 }
284
285 List<Map<String, String>> propertiesList = _buildPropertiesList(
286 modelType);
287
288 if (propertiesList != null) {
289 map.put("properties", propertiesList);
290 }
291
292 map.put("type", type.getName());
293 }
294
295 return types;
296 }
297
298 private String _formatType(
299 Class<?> type, Class<?>[] genericTypes, boolean returnType) {
300
301 if (type.isArray()) {
302 Class<?> componentType = type.getComponentType();
303
304 return _formatType(componentType, genericTypes, returnType) + "[]";
305 }
306
307 if (type.isPrimitive()) {
308 return type.getSimpleName();
309 }
310
311 if (type.equals(Boolean.class)) {
312 return "boolean";
313 }
314 else if (type.equals(Class.class)) {
315 if (!returnType) {
316 return "string";
317 }
318 }
319 else if (type.equals(Date.class)) {
320 return "long";
321 }
322 else if (type.equals(File.class)) {
323 if (!returnType) {
324 return "file";
325 }
326 else {
327 type = FileData.class;
328 }
329 }
330 else if (type.equals(Locale.class) || type.equals(String.class) ||
331 type.equals(TimeZone.class)) {
332
333 return "string";
334 }
335 else if (type.equals(Object.class) || type.equals(Serializable.class)) {
336 return "map";
337 }
338 else if (ReflectUtil.isTypeOf(type, Number.class)) {
339 String typeName = null;
340
341 if (type == Character.class) {
342 typeName = "char";
343 }
344 else if (type == Integer.class) {
345 typeName = "int";
346 }
347 else {
348 typeName = StringUtil.toLowerCase(type.getSimpleName());
349 }
350
351 return typeName;
352 }
353
354 String typeName = type.getName();
355
356 if ((type == Collection.class) ||
357 ReflectUtil.isTypeOf(type, List.class)) {
358
359 typeName = "list";
360 }
361 else if (ReflectUtil.isTypeOf(type, Map.class)) {
362 typeName = "map";
363 }
364 else {
365 if (!_types.contains(type)) {
366 _types.add(type);
367 }
368 }
369
370 if (genericTypes == null) {
371 return typeName;
372 }
373
374 StringBundler sb = new StringBundler(genericTypes.length * 2 + 1);
375
376 sb.append(StringPool.LESS_THAN);
377
378 for (int i = 0; i < genericTypes.length; i++) {
379 Class<?> genericType = genericTypes[i];
380
381 if (i != 0) {
382 sb.append(StringPool.COMMA);
383 }
384
385 if (genericType == null) {
386 sb.append(StringPool.STAR);
387 }
388 else {
389 sb.append(_formatType(genericType, null, returnType));
390 }
391 }
392
393 sb.append(StringPool.GREATER_THAN);
394
395 return typeName + sb.toString();
396 }
397
398 private Class<?>[] _getGenericReturnTypes(
399 JSONWebServiceActionMapping jsonWebServiceActionMapping) {
400
401 Method realActionMethod =
402 jsonWebServiceActionMapping.getRealActionMethod();
403
404 Type genericReturnType = realActionMethod.getGenericReturnType();
405
406 if (!(genericReturnType instanceof ParameterizedType)) {
407 return null;
408 }
409
410 ParameterizedType parameterizedType =
411 (ParameterizedType)genericReturnType;
412
413 Type[] genericTypes = parameterizedType.getActualTypeArguments();
414
415 Class<?>[] genericReturnTypes = new Class[genericTypes.length];
416
417 for (int i = 0; i < genericTypes.length; i++) {
418 Type genericType = genericTypes[i];
419
420 genericReturnTypes[i] = ReflectUtil.getRawType(
421 genericType, jsonWebServiceActionMapping.getActionClass());
422 }
423
424 return genericReturnTypes;
425 }
426
427 private String _getName(
428 JSONWebServiceActionMapping jsonWebServiceActionMapping) {
429
430 Class<?> clazz = jsonWebServiceActionMapping.getActionClass();
431
432 String className =
433 _jsonWebServiceNaming.convertServiceClassToSimpleName(clazz);
434
435 Method method = jsonWebServiceActionMapping.getRealActionMethod();
436
437 return className.concat(StringPool.POUND).concat(method.getName());
438 }
439
440 private String _basePath;
441 private String _baseURL;
442 private String _contextName;
443 private JSONWebServiceNaming _jsonWebServiceNaming;
444 private List<Class<?>> _types = new ArrayList<Class<?>>();
445
446 }