/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.jsonwebservice.action; import com.liferay.portal.json.data.FileData; import com.liferay.portal.json.transformer.BeanAnalyzerTransformer; import com.liferay.portal.kernel.javadoc.JavadocManagerUtil; import com.liferay.portal.kernel.javadoc.JavadocMethod; import com.liferay.portal.kernel.json.JSONFactoryUtil; import com.liferay.portal.kernel.json.JSONSerializable; import com.liferay.portal.kernel.json.JSONSerializer; import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceAction; import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionMapping; import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionsManagerUtil; import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceNaming; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.MethodParameter; import com.liferay.portal.kernel.util.ParamUtil; import com.liferay.portal.kernel.util.ReleaseInfo; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import java.io.File; import java.io.Serializable; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.TimeZone; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import jodd.util.ReflectUtil; /** * @author Igor Spasic * @author Raymond Augé */ public class JSONWebServiceDiscoverAction implements JSONWebServiceAction { public JSONWebServiceDiscoverAction(HttpServletRequest request) { _basePath = request.getServletPath(); _baseURL = String.valueOf(request.getRequestURL()); ServletContext servletContext = request.getServletContext(); _contextName = GetterUtil.getString( ParamUtil.getString( request, "contextName", servletContext.getServletContextName())); _jsonWebServiceNaming = JSONWebServiceActionsManagerUtil.getJSONWebServiceNaming(); } @Override public JSONWebServiceActionMapping getJSONWebServiceActionMapping() { return null; } @Override public Object invoke() throws Exception { Map<String, Object> resultsMap = new LinkedHashMap<>(); resultsMap.put("contextName", _contextName); resultsMap.put("basePath", _basePath); resultsMap.put("baseURL", _baseURL); resultsMap.put("services", _buildJsonWebServiceActionMappingMaps()); resultsMap.put("types", _buildTypes()); resultsMap.put("version", ReleaseInfo.getVersion()); return new DiscoveryContent(resultsMap); } public static class DiscoveryContent implements JSONSerializable { public DiscoveryContent(Map<String, Object> resultsMap) { _resultsMap = resultsMap; } @Override public String toJSONString() { JSONSerializer jsonSerializer = JSONFactoryUtil.createJSONSerializer(); jsonSerializer.include("types"); return jsonSerializer.serializeDeep(_resultsMap); } private final Map<String, Object> _resultsMap; } private List<Map<String, Object>> _buildJsonWebServiceActionMappingMaps() { List<JSONWebServiceActionMapping> jsonWebServiceActionMappings = JSONWebServiceActionsManagerUtil.getJSONWebServiceActionMappings( _contextName); List<Map<String, Object>> jsonWebServiceActionMappingMaps = new ArrayList<>(jsonWebServiceActionMappings.size()); for (JSONWebServiceActionMapping jsonWebServiceActionMapping : jsonWebServiceActionMappings) { String path = jsonWebServiceActionMapping.getPath(); Map<String, Object> jsonWebServiceActionMappingMap = new LinkedHashMap<>(); if (jsonWebServiceActionMapping.isDeprecated()) { jsonWebServiceActionMappingMap.put("deprecated", Boolean.TRUE); } JavadocMethod javadocMethod = JavadocManagerUtil.lookupJavadocMethod( jsonWebServiceActionMapping.getRealActionMethod()); if (javadocMethod != null) { String methodComment = javadocMethod.getComment(); if (methodComment != null) { jsonWebServiceActionMappingMap.put( "description", javadocMethod.getComment()); } } jsonWebServiceActionMappingMap.put( "method", jsonWebServiceActionMapping.getMethod()); jsonWebServiceActionMappingMap.put( "name", _getName(jsonWebServiceActionMapping)); MethodParameter[] methodParameters = jsonWebServiceActionMapping.getMethodParameters(); List<Map<String, String>> parametersList = new ArrayList<>( methodParameters.length); for (int i = 0; i < methodParameters.length; i++) { MethodParameter methodParameter = methodParameters[i]; Class<?>[] genericTypes = methodParameter.getGenericTypes(); Map<String, String> parameterMap = new HashMap<>(); if (javadocMethod != null) { String parameterComment = javadocMethod.getParameterComment( i); if (!Validator.isBlank(parameterComment)) { parameterMap.put("description", parameterComment); } } parameterMap.put("name", methodParameter.getName()); parameterMap.put( "type", _formatType( methodParameter.getType(), genericTypes, false)); parametersList.add(parameterMap); } jsonWebServiceActionMappingMap.put("parameters", parametersList); jsonWebServiceActionMappingMap.put("path", path); Map<String, String> returnsMap = new LinkedHashMap<>(); if (javadocMethod != null) { String returnComment = javadocMethod.getReturnComment(); if (!Validator.isBlank(returnComment)) { returnsMap.put("description", returnComment); } } Method actionMethod = jsonWebServiceActionMapping.getActionMethod(); returnsMap.put( "type", _formatType( actionMethod.getReturnType(), _getGenericReturnTypes(jsonWebServiceActionMapping), true)); jsonWebServiceActionMappingMap.put("returns", returnsMap); jsonWebServiceActionMappingMaps.add(jsonWebServiceActionMappingMap); } return jsonWebServiceActionMappingMaps; } private List<Map<String, String>> _buildPropertiesList(Class<?> type) { try { BeanAnalyzerTransformer beanAnalyzerTransformer = new BeanAnalyzerTransformer(type) { @Override protected String getTypeName(Class<?> type) { return _formatType(type, null, false); } }; return beanAnalyzerTransformer.collect(); } catch (Exception e) { return null; } } private List<Map<String, Object>> _buildTypes() { List<Map<String, Object>> types = new ArrayList<>(); for (int i = 0; i < _types.size(); i++) { Class<?> type = _types.get(i); Map<String, Object> map = new LinkedHashMap<>(); types.add(map); Class<?> modelType = type; if (type.isInterface()) { try { Class<?> clazz = getClass(); ClassLoader classLoader = clazz.getClassLoader(); String modelImplClassName = _jsonWebServiceNaming.convertModelClassToImplClassName( type); modelType = classLoader.loadClass(modelImplClassName); } catch (ClassNotFoundException cnfe) { } } if (modelType.isInterface() || Modifier.isAbstract(modelType.getModifiers())) { map.put("interface", Boolean.TRUE); } List<Map<String, String>> propertiesList = _buildPropertiesList( modelType); if (propertiesList != null) { map.put("properties", propertiesList); } map.put("type", type.getName()); } return types; } private String _formatType( Class<?> type, Class<?>[] genericTypes, boolean returnType) { if (type.isArray()) { Class<?> componentType = type.getComponentType(); return _formatType(componentType, genericTypes, returnType) + "[]"; } if (type.isPrimitive()) { return type.getSimpleName(); } if (type.equals(Boolean.class)) { return "boolean"; } else if (type.equals(Class.class)) { if (!returnType) { return "string"; } } else if (type.equals(Date.class)) { return "long"; } else if (type.equals(File.class)) { if (!returnType) { return "file"; } else { type = FileData.class; } } else if (type.equals(Locale.class) || type.equals(String.class) || type.equals(TimeZone.class)) { return "string"; } else if (type.equals(Object.class) || type.equals(Serializable.class)) { return "map"; } else if (ReflectUtil.isTypeOf(type, Number.class)) { String typeName = null; if (type == Character.class) { typeName = "char"; } else if (type == Integer.class) { typeName = "int"; } else { typeName = StringUtil.toLowerCase(type.getSimpleName()); } return typeName; } String typeName = type.getName(); if ((type == Collection.class) || ReflectUtil.isTypeOf(type, List.class)) { typeName = "list"; } else if (ReflectUtil.isTypeOf(type, Map.class)) { typeName = "map"; } else { if (!_types.contains(type)) { _types.add(type); } } if (genericTypes == null) { return typeName; } StringBundler sb = new StringBundler(genericTypes.length * 2 + 1); sb.append(StringPool.LESS_THAN); for (int i = 0; i < genericTypes.length; i++) { Class<?> genericType = genericTypes[i]; if (i != 0) { sb.append(StringPool.COMMA); } if (genericType == null) { sb.append(StringPool.STAR); } else { sb.append(_formatType(genericType, null, returnType)); } } sb.append(StringPool.GREATER_THAN); return typeName + sb.toString(); } private Class<?>[] _getGenericReturnTypes( JSONWebServiceActionMapping jsonWebServiceActionMapping) { Method realActionMethod = jsonWebServiceActionMapping.getRealActionMethod(); Type genericReturnType = realActionMethod.getGenericReturnType(); if (!(genericReturnType instanceof ParameterizedType)) { return null; } ParameterizedType parameterizedType = (ParameterizedType)genericReturnType; Type[] genericTypes = parameterizedType.getActualTypeArguments(); Class<?>[] genericReturnTypes = new Class<?>[genericTypes.length]; for (int i = 0; i < genericTypes.length; i++) { Type genericType = genericTypes[i]; genericReturnTypes[i] = ReflectUtil.getRawType( genericType, jsonWebServiceActionMapping.getActionClass()); } return genericReturnTypes; } private String _getName( JSONWebServiceActionMapping jsonWebServiceActionMapping) { Class<?> clazz = jsonWebServiceActionMapping.getActionClass(); String className = _jsonWebServiceNaming.convertServiceClassToSimpleName(clazz); Method method = jsonWebServiceActionMapping.getRealActionMethod(); return className.concat(StringPool.POUND).concat(method.getName()); } private final String _basePath; private final String _baseURL; private final String _contextName; private final JSONWebServiceNaming _jsonWebServiceNaming; private final List<Class<?>> _types = new ArrayList<>(); }