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