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<>();
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 final 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<>(jsonWebServiceActionMappings.size());
129
130 for (JSONWebServiceActionMapping jsonWebServiceActionMapping :
131 jsonWebServiceActionMappings) {
132
133 String path = jsonWebServiceActionMapping.getPath();
134
135 Map<String, Object> jsonWebServiceActionMappingMap =
136 new LinkedHashMap<>();
137
138 if (jsonWebServiceActionMapping.isDeprecated()) {
139 jsonWebServiceActionMappingMap.put("deprecated", Boolean.TRUE);
140 }
141
142 JavadocMethod javadocMethod =
143 JavadocManagerUtil.lookupJavadocMethod(
144 jsonWebServiceActionMapping.getRealActionMethod());
145
146 if (javadocMethod != null) {
147 String methodComment = javadocMethod.getComment();
148
149 if (methodComment != null) {
150 jsonWebServiceActionMappingMap.put(
151 "description", javadocMethod.getComment());
152 }
153 }
154
155 jsonWebServiceActionMappingMap.put(
156 "method", jsonWebServiceActionMapping.getMethod());
157
158 jsonWebServiceActionMappingMap.put(
159 "name", _getName(jsonWebServiceActionMapping));
160
161 MethodParameter[] methodParameters =
162 jsonWebServiceActionMapping.getMethodParameters();
163
164 List<Map<String, String>> parametersList = new ArrayList<>(
165 methodParameters.length);
166
167 for (int i = 0; i < methodParameters.length; i++) {
168 MethodParameter methodParameter = methodParameters[i];
169
170 Class<?>[] genericTypes = null;
171
172 try {
173 genericTypes = methodParameter.getGenericTypes();
174 }
175 catch (ClassNotFoundException cnfe) {
176 throw new PortalException(cnfe);
177 }
178
179 Map<String, String> parameterMap = new HashMap<>();
180
181 if (javadocMethod != null) {
182 String parameterComment = javadocMethod.getParameterComment(
183 i);
184
185 if (!Validator.isBlank(parameterComment)) {
186 parameterMap.put("description", parameterComment);
187 }
188 }
189
190 parameterMap.put("name", methodParameter.getName());
191 parameterMap.put(
192 "type",
193 _formatType(
194 methodParameter.getType(), genericTypes, false));
195
196 parametersList.add(parameterMap);
197 }
198
199 jsonWebServiceActionMappingMap.put("parameters", parametersList);
200
201 jsonWebServiceActionMappingMap.put("path", path);
202
203 Map<String, String> returnsMap = new LinkedHashMap<>();
204
205 if (javadocMethod != null) {
206 String returnComment = javadocMethod.getReturnComment();
207
208 if (!Validator.isBlank(returnComment)) {
209 returnsMap.put("description", returnComment);
210 }
211 }
212
213 Method actionMethod = jsonWebServiceActionMapping.getActionMethod();
214
215 returnsMap.put(
216 "type",
217 _formatType(
218 actionMethod.getReturnType(),
219 _getGenericReturnTypes(jsonWebServiceActionMapping), true));
220
221 jsonWebServiceActionMappingMap.put("returns", returnsMap);
222
223 jsonWebServiceActionMappingMaps.add(jsonWebServiceActionMappingMap);
224 }
225
226 return jsonWebServiceActionMappingMaps;
227 }
228
229 private List<Map<String, String>> _buildPropertiesList(Class<?> type) {
230 try {
231 BeanAnalyzerTransformer beanAnalyzerTransformer =
232 new BeanAnalyzerTransformer(type) {
233
234 @Override
235 protected String getTypeName(Class<?> type) {
236 return _formatType(type, null, false);
237 }
238
239 };
240
241 return beanAnalyzerTransformer.collect();
242 }
243 catch (Exception e) {
244 return null;
245 }
246 }
247
248 private List<Map<String, Object>> _buildTypes() {
249 List<Map<String, Object>> types = new ArrayList<>();
250
251 for (int i = 0; i < _types.size(); i++) {
252 Class<?> type = _types.get(i);
253
254 Map<String, Object> map = new LinkedHashMap<>();
255
256 types.add(map);
257
258 Class<?> modelType = type;
259
260 if (type.isInterface()) {
261 try {
262 Class<?> clazz = getClass();
263
264 ClassLoader classLoader = clazz.getClassLoader();
265
266 String modelImplClassName =
267 _jsonWebServiceNaming.convertModelClassToImplClassName(
268 type);
269
270 modelType = classLoader.loadClass(modelImplClassName);
271 }
272 catch (ClassNotFoundException cnfe) {
273 }
274 }
275
276 if (modelType.isInterface() ||
277 Modifier.isAbstract(modelType.getModifiers())) {
278
279 map.put("interface", Boolean.TRUE);
280 }
281
282 List<Map<String, String>> propertiesList = _buildPropertiesList(
283 modelType);
284
285 if (propertiesList != null) {
286 map.put("properties", propertiesList);
287 }
288
289 map.put("type", type.getName());
290 }
291
292 return types;
293 }
294
295 private String _formatType(
296 Class<?> type, Class<?>[] genericTypes, boolean returnType) {
297
298 if (type.isArray()) {
299 Class<?> componentType = type.getComponentType();
300
301 return _formatType(componentType, genericTypes, returnType) + "[]";
302 }
303
304 if (type.isPrimitive()) {
305 return type.getSimpleName();
306 }
307
308 if (type.equals(Boolean.class)) {
309 return "boolean";
310 }
311 else if (type.equals(Class.class)) {
312 if (!returnType) {
313 return "string";
314 }
315 }
316 else if (type.equals(Date.class)) {
317 return "long";
318 }
319 else if (type.equals(File.class)) {
320 if (!returnType) {
321 return "file";
322 }
323 else {
324 type = FileData.class;
325 }
326 }
327 else if (type.equals(Locale.class) || type.equals(String.class) ||
328 type.equals(TimeZone.class)) {
329
330 return "string";
331 }
332 else if (type.equals(Object.class) || type.equals(Serializable.class)) {
333 return "map";
334 }
335 else if (ReflectUtil.isTypeOf(type, Number.class)) {
336 String typeName = null;
337
338 if (type == Character.class) {
339 typeName = "char";
340 }
341 else if (type == Integer.class) {
342 typeName = "int";
343 }
344 else {
345 typeName = StringUtil.toLowerCase(type.getSimpleName());
346 }
347
348 return typeName;
349 }
350
351 String typeName = type.getName();
352
353 if ((type == Collection.class) ||
354 ReflectUtil.isTypeOf(type, List.class)) {
355
356 typeName = "list";
357 }
358 else if (ReflectUtil.isTypeOf(type, Map.class)) {
359 typeName = "map";
360 }
361 else {
362 if (!_types.contains(type)) {
363 _types.add(type);
364 }
365 }
366
367 if (genericTypes == null) {
368 return typeName;
369 }
370
371 StringBundler sb = new StringBundler(genericTypes.length * 2 + 1);
372
373 sb.append(StringPool.LESS_THAN);
374
375 for (int i = 0; i < genericTypes.length; i++) {
376 Class<?> genericType = genericTypes[i];
377
378 if (i != 0) {
379 sb.append(StringPool.COMMA);
380 }
381
382 if (genericType == null) {
383 sb.append(StringPool.STAR);
384 }
385 else {
386 sb.append(_formatType(genericType, null, returnType));
387 }
388 }
389
390 sb.append(StringPool.GREATER_THAN);
391
392 return typeName + sb.toString();
393 }
394
395 private Class<?>[] _getGenericReturnTypes(
396 JSONWebServiceActionMapping jsonWebServiceActionMapping) {
397
398 Method realActionMethod =
399 jsonWebServiceActionMapping.getRealActionMethod();
400
401 Type genericReturnType = realActionMethod.getGenericReturnType();
402
403 if (!(genericReturnType instanceof ParameterizedType)) {
404 return null;
405 }
406
407 ParameterizedType parameterizedType =
408 (ParameterizedType)genericReturnType;
409
410 Type[] genericTypes = parameterizedType.getActualTypeArguments();
411
412 Class<?>[] genericReturnTypes = new Class[genericTypes.length];
413
414 for (int i = 0; i < genericTypes.length; i++) {
415 Type genericType = genericTypes[i];
416
417 genericReturnTypes[i] = ReflectUtil.getRawType(
418 genericType, jsonWebServiceActionMapping.getActionClass());
419 }
420
421 return genericReturnTypes;
422 }
423
424 private String _getName(
425 JSONWebServiceActionMapping jsonWebServiceActionMapping) {
426
427 Class<?> clazz = jsonWebServiceActionMapping.getActionClass();
428
429 String className =
430 _jsonWebServiceNaming.convertServiceClassToSimpleName(clazz);
431
432 Method method = jsonWebServiceActionMapping.getRealActionMethod();
433
434 return className.concat(StringPool.POUND).concat(method.getName());
435 }
436
437 private final String _basePath;
438 private final String _baseURL;
439 private final String _contextName;
440 private final JSONWebServiceNaming _jsonWebServiceNaming;
441 private final List<Class<?>> _types = new ArrayList<>();
442
443 }