001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.jsonwebservice.action;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.json.JSONFactoryUtil;
019    import com.liferay.portal.kernel.json.JSONSerializable;
020    import com.liferay.portal.kernel.json.JSONSerializer;
021    import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceAction;
022    import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionMapping;
023    import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionsManagerUtil;
024    import com.liferay.portal.kernel.util.MethodParameter;
025    import com.liferay.portal.kernel.util.StringBundler;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.kernel.util.StringUtil;
028    
029    import java.io.Serializable;
030    
031    import java.lang.reflect.Method;
032    
033    import java.util.ArrayList;
034    import java.util.Arrays;
035    import java.util.Date;
036    import java.util.HashMap;
037    import java.util.LinkedHashMap;
038    import java.util.List;
039    import java.util.Locale;
040    import java.util.Map;
041    
042    import javax.servlet.http.HttpServletRequest;
043    
044    import jodd.util.Wildcard;
045    
046    /**
047     * @author Igor Spasic
048     */
049    public class JSONWebServiceDiscoverAction implements JSONWebServiceAction {
050    
051            public JSONWebServiceDiscoverAction(HttpServletRequest request) {
052                    _basePath = request.getServletPath();
053                    _baseURL = request.getRequestURL().toString();
054                    _contextPath = request.getContextPath();
055    
056                    String discover = request.getParameter("discover");
057    
058                    _discover = StringUtil.split(discover);
059            }
060    
061            @Override
062            public JSONWebServiceActionMapping getJSONWebServiceActionMapping() {
063                    return null;
064            }
065    
066            @Override
067            public Object invoke() throws Exception {
068                    Map<String, Object> resultsMap = new LinkedHashMap<String, Object>();
069    
070                    Map<String, Object> jsonWebServiceActionMappingMaps =
071                            _buildJsonWebServiceActionMappingMaps();
072    
073                    resultsMap.put("actions", jsonWebServiceActionMappingMaps);
074    
075                    resultsMap.put("context", _contextPath);
076                    resultsMap.put("basePath", _basePath);
077                    resultsMap.put("baseURL", _baseURL);
078    
079                    if (_discover.length > 0) {
080                            resultsMap.put("discover", Arrays.toString(_discover));
081                    }
082    
083                    return new DiscoveryContent(resultsMap);
084            }
085    
086            public static class DiscoveryContent implements JSONSerializable {
087    
088                    public DiscoveryContent(Map<String, Object> resultsMap) {
089                            _resultsMap = resultsMap;
090                    }
091    
092                    @Override
093                    public String toJSONString() {
094                            JSONSerializer jsonSerializer =
095                                    JSONFactoryUtil.createJSONSerializer();
096    
097                            jsonSerializer.include("*.parameters");
098    
099                            return jsonSerializer.serialize(_resultsMap);
100                    }
101    
102                    private Map<String, Object> _resultsMap;
103    
104            }
105    
106            private Map<String, Object> _buildJsonWebServiceActionMappingMaps()
107                    throws PortalException {
108    
109                    List<JSONWebServiceActionMapping> jsonWebServiceActionMappingMaps =
110                            JSONWebServiceActionsManagerUtil.getJSONWebServiceActionMappings(
111                                    _contextPath);
112    
113                    Map<String, Object> jsonWebServiceActionMappingsMap =
114                            new LinkedHashMap<String, Object>(
115                                    jsonWebServiceActionMappingMaps.size());
116    
117                    for (JSONWebServiceActionMapping jsonWebServiceActionMapping :
118                                    jsonWebServiceActionMappingMaps) {
119    
120                            String path = jsonWebServiceActionMapping.getPath();
121    
122                            if (!_isAcceptPath(path)) {
123                                    continue;
124                            }
125    
126                            Map<String, Object> jsonWebServiceActionMappingMap =
127                                    new LinkedHashMap<String, Object>();
128    
129                            jsonWebServiceActionMappingMap.put(
130                                    "method", jsonWebServiceActionMapping.getMethod());
131    
132                            MethodParameter[] methodParameters =
133                                    jsonWebServiceActionMapping.getMethodParameters();
134    
135                            List<Map<String, String>> parametersList =
136                                    new ArrayList<Map<String, String>>(methodParameters.length);
137    
138                            for (MethodParameter methodParameter : methodParameters) {
139                                    Class<?>[] genericTypes = null;
140    
141                                    try {
142                                            genericTypes = methodParameter.getGenericTypes();
143                                    }
144                                    catch (ClassNotFoundException cnfe) {
145                                            throw new PortalException(cnfe);
146                                    }
147    
148                                    Map<String, String> parameterMap =
149                                            new HashMap<String, String>();
150    
151                                    parameterMap.put("name", methodParameter.getName());
152                                    parameterMap.put(
153                                            "type",
154                                            _formatType(methodParameter.getType(), genericTypes));
155    
156                                    parametersList.add(parameterMap);
157                            }
158    
159                            jsonWebServiceActionMappingMap.put("parameters", parametersList);
160    
161                            jsonWebServiceActionMappingMap.put("path", path);
162    
163                            Method actionMethod = jsonWebServiceActionMapping.getActionMethod();
164    
165                            jsonWebServiceActionMappingMap.put(
166                                    "response", _formatType(actionMethod.getReturnType(), null));
167    
168                            jsonWebServiceActionMappingsMap.put(
169                                    path, jsonWebServiceActionMappingMap);
170                    }
171    
172                    return jsonWebServiceActionMappingsMap;
173            }
174    
175            private String _formatType(Class<?> type, Class<?>[] genericTypes) {
176                    if (type.isArray()) {
177                            Class<?> componentType = type.getComponentType();
178    
179                            return _formatType(componentType, genericTypes) + "[]";
180                    }
181    
182                    if (type.isPrimitive()) {
183                            return type.getSimpleName();
184                    }
185                    else if (type.equals(Date.class)) {
186                            return "long";
187                    }
188                    else if (type.equals(Locale.class) || type.equals(String.class)) {
189                            return "string";
190                    }
191                    else if (type.equals(Object.class) || type.equals(Serializable.class)) {
192                            return "object";
193                    }
194    
195                    String typeName = type.getName();
196    
197                    if (type.equals(List.class)) {
198                            typeName = "list";
199                    }
200                    else if (type.equals(Map.class)) {
201                            typeName = "map";
202                    }
203                    else {
204                            _types.add(type);
205                    }
206    
207                    if (genericTypes == null) {
208                            return "object<" + typeName + ">";
209                    }
210    
211                    StringBundler sb = new StringBundler(genericTypes.length * 2 + 1);
212    
213                    sb.append(StringPool.LESS_THAN);
214    
215                    for (int i = 0; i < genericTypes.length; i++) {
216                            Class<?> genericType = genericTypes[i];
217    
218                            if (i != 0) {
219                                    sb.append(StringPool.COMMA);
220                            }
221    
222                            sb.append(_formatType(genericType, null));
223                    }
224    
225                    sb.append(StringPool.GREATER_THAN);
226    
227                    return typeName + sb.toString();
228            }
229    
230            private boolean _isAcceptPath(String path) {
231                    if (_discover.length == 0) {
232                            return true;
233                    }
234    
235                    if (Wildcard.matchOne(path, _discover) != -1) {
236                            return true;
237                    }
238                    else {
239                            return false;
240                    }
241            }
242    
243            private String _basePath;
244            private String _baseURL;
245            private String _contextPath;
246            private String[] _discover;
247            private List<Class<?>> _types = new ArrayList<Class<?>>();
248    
249    }