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.Date;
035    import java.util.HashMap;
036    import java.util.LinkedHashMap;
037    import java.util.List;
038    import java.util.Locale;
039    import java.util.Map;
040    
041    import javax.servlet.http.HttpServletRequest;
042    
043    import jodd.util.Wildcard;
044    
045    /**
046     * @author Igor Spasic
047     */
048    public class JSONWebServiceDiscoverAction implements JSONWebServiceAction {
049    
050            public JSONWebServiceDiscoverAction(HttpServletRequest request) {
051                    _basePath = request.getServletPath();
052                    _baseURL = request.getRequestURL().toString();
053                    _contextPath = request.getContextPath();
054    
055                    String discover = request.getParameter("discover");
056    
057                    _discover = StringUtil.split(discover);
058            }
059    
060            @Override
061            public JSONWebServiceActionMapping getJSONWebServiceActionMapping() {
062                    return null;
063            }
064    
065            @Override
066            public Object invoke() throws Exception {
067                    Map<String, Object> resultsMap = new LinkedHashMap<String, Object>();
068    
069                    List<Map<String, Object>> jsonWebServiceActionMappingMaps =
070                            _buildJsonWebServiceActionMappingMaps();
071    
072                    resultsMap.put("actions", jsonWebServiceActionMappingMaps);
073    
074                    resultsMap.put("context", _contextPath);
075                    resultsMap.put("basePath", _basePath);
076                    resultsMap.put("baseURL", _baseURL);
077    
078                    if (_discover.length > 0) {
079                            resultsMap.put("discover", _discover);
080                    }
081    
082                    return new DiscoveryContent(resultsMap);
083            }
084    
085            public static class DiscoveryContent implements JSONSerializable {
086    
087                    public DiscoveryContent(Map<String, Object> resultsMap) {
088                            _resultsMap = resultsMap;
089                    }
090    
091                    @Override
092                    public String toJSONString() {
093                            JSONSerializer jsonSerializer =
094                                    JSONFactoryUtil.createJSONSerializer();
095    
096                            return jsonSerializer.serializeDeep(_resultsMap);
097                    }
098    
099                    private Map<String, Object> _resultsMap;
100    
101            }
102    
103            private List<Map<String, Object>> _buildJsonWebServiceActionMappingMaps()
104                    throws PortalException {
105    
106                    List<JSONWebServiceActionMapping> jsonWebServiceActionMappings =
107                            JSONWebServiceActionsManagerUtil.getJSONWebServiceActionMappings(
108                                    _contextPath);
109    
110                    List<Map<String, Object>> jsonWebServiceActionMappingMaps =
111                            new ArrayList<Map<String, Object>>(
112                                    jsonWebServiceActionMappings.size());
113    
114                    for (JSONWebServiceActionMapping jsonWebServiceActionMapping :
115                                    jsonWebServiceActionMappings) {
116    
117                            String path = jsonWebServiceActionMapping.getPath();
118    
119                            if (!_isAcceptPath(path)) {
120                                    continue;
121                            }
122    
123                            Map<String, Object> jsonWebServiceActionMappingMap =
124                                    new LinkedHashMap<String, Object>();
125    
126                            jsonWebServiceActionMappingMap.put(
127                                    "method", jsonWebServiceActionMapping.getMethod());
128    
129                            MethodParameter[] methodParameters =
130                                    jsonWebServiceActionMapping.getMethodParameters();
131    
132                            List<Map<String, String>> parametersList =
133                                    new ArrayList<Map<String, String>>(methodParameters.length);
134    
135                            for (MethodParameter methodParameter : methodParameters) {
136                                    Class<?>[] genericTypes = null;
137    
138                                    try {
139                                            genericTypes = methodParameter.getGenericTypes();
140                                    }
141                                    catch (ClassNotFoundException cnfe) {
142                                            throw new PortalException(cnfe);
143                                    }
144    
145                                    Map<String, String> parameterMap =
146                                            new HashMap<String, String>();
147    
148                                    parameterMap.put("name", methodParameter.getName());
149                                    parameterMap.put(
150                                            "type",
151                                            _formatType(methodParameter.getType(), genericTypes));
152    
153                                    parametersList.add(parameterMap);
154                            }
155    
156                            jsonWebServiceActionMappingMap.put("parameters", parametersList);
157    
158                            jsonWebServiceActionMappingMap.put("path", path);
159    
160                            Method actionMethod = jsonWebServiceActionMapping.getActionMethod();
161    
162                            jsonWebServiceActionMappingMap.put(
163                                    "response", _formatType(actionMethod.getReturnType(), null));
164    
165                            jsonWebServiceActionMappingMaps.add(jsonWebServiceActionMappingMap);
166                    }
167    
168                    return jsonWebServiceActionMappingMaps;
169            }
170    
171            private String _formatType(Class<?> type, Class<?>[] genericTypes) {
172                    if (type.isArray()) {
173                            Class<?> componentType = type.getComponentType();
174    
175                            return _formatType(componentType, genericTypes) + "[]";
176                    }
177    
178                    if (type.isPrimitive()) {
179                            return type.getSimpleName();
180                    }
181                    else if (type.equals(Date.class)) {
182                            return "long";
183                    }
184                    else if (type.equals(Locale.class) || type.equals(String.class)) {
185                            return "string";
186                    }
187                    else if (type.equals(Object.class) || type.equals(Serializable.class)) {
188                            return "object";
189                    }
190    
191                    String typeName = type.getName();
192    
193                    if (type.equals(List.class)) {
194                            typeName = "list";
195                    }
196                    else if (type.equals(Map.class)) {
197                            typeName = "map";
198                    }
199                    else {
200                            _types.add(type);
201                    }
202    
203                    if (genericTypes == null) {
204                            return "object<" + typeName + ">";
205                    }
206    
207                    StringBundler sb = new StringBundler(genericTypes.length * 2 + 1);
208    
209                    sb.append(StringPool.LESS_THAN);
210    
211                    for (int i = 0; i < genericTypes.length; i++) {
212                            Class<?> genericType = genericTypes[i];
213    
214                            if (i != 0) {
215                                    sb.append(StringPool.COMMA);
216                            }
217    
218                            sb.append(_formatType(genericType, null));
219                    }
220    
221                    sb.append(StringPool.GREATER_THAN);
222    
223                    return typeName + sb.toString();
224            }
225    
226            private boolean _isAcceptPath(String path) {
227                    if (_discover.length == 0) {
228                            return true;
229                    }
230    
231                    if (Wildcard.matchOne(path, _discover) != -1) {
232                            return true;
233                    }
234                    else {
235                            return false;
236                    }
237            }
238    
239            private String _basePath;
240            private String _baseURL;
241            private String _contextPath;
242            private String[] _discover;
243            private List<Class<?>> _types = new ArrayList<Class<?>>();
244    
245    }