001    /**
002     * Copyright (c) 2000-2012 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;
016    
017    import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceAction;
018    import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionMapping;
019    import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionsManager;
020    import com.liferay.portal.kernel.servlet.HttpMethods;
021    import com.liferay.portal.kernel.util.BinarySearch;
022    import com.liferay.portal.kernel.util.CharPool;
023    import com.liferay.portal.kernel.util.ContextPathUtil;
024    import com.liferay.portal.kernel.util.GetterUtil;
025    import com.liferay.portal.kernel.util.MethodParameter;
026    import com.liferay.portal.kernel.util.SortedArrayList;
027    import com.liferay.portal.kernel.util.StringPool;
028    import com.liferay.portal.util.PortalUtil;
029    import com.liferay.portal.util.PropsValues;
030    
031    import java.lang.reflect.Method;
032    
033    import java.util.ArrayList;
034    import java.util.Iterator;
035    import java.util.List;
036    
037    import javax.servlet.ServletContext;
038    import javax.servlet.http.HttpServletRequest;
039    import javax.servlet.http.HttpSession;
040    
041    /**
042     * @author Igor Spasic
043     */
044    public class JSONWebServiceActionsManagerImpl
045            implements JSONWebServiceActionsManager {
046    
047            public JSONWebServiceAction getJSONWebServiceAction(
048                    HttpServletRequest request) {
049    
050                    String path = GetterUtil.getString(request.getPathInfo());
051    
052                    String method = GetterUtil.getString(request.getMethod());
053    
054                    String pathParameters = null;
055    
056                    JSONRPCRequest jsonRpcRequest = null;
057    
058                    int pathParametersIndex = _getPathParametersIndex(path);
059    
060                    if (pathParametersIndex != -1) {
061                            pathParameters = path.substring(pathParametersIndex);
062    
063                            path = path.substring(0, pathParametersIndex);
064                    }
065                    else {
066                            if (method.equals(HttpMethods.POST) &&
067                                    !PortalUtil.isMultipartRequest(request)) {
068    
069                                    jsonRpcRequest = JSONRPCRequest.detectJSONRPCRequest(request);
070    
071                                    if (jsonRpcRequest != null) {
072                                            path += StringPool.SLASH + jsonRpcRequest.getMethod();
073    
074                                            method = null;
075                                    }
076                            }
077                    }
078    
079                    JSONWebServiceActionParameters jsonWebServiceActionParameters =
080                            new JSONWebServiceActionParameters();
081    
082                    jsonWebServiceActionParameters.collectAll(
083                            request, pathParameters, jsonRpcRequest);
084    
085                    String[] parameterNames =
086                            jsonWebServiceActionParameters.getParameterNames();
087    
088                    HttpSession session = request.getSession();
089    
090                    ServletContext servletContext = session.getServletContext();
091    
092                    String servletContextPath = ContextPathUtil.getContextPath(
093                            servletContext);
094    
095                    int jsonWebServiceActionConfigIndex =
096                            _getJSONWebServiceActionConfigIndex(
097                                    servletContextPath, path, method, parameterNames);
098    
099                    if (jsonWebServiceActionConfigIndex == -1) {
100                            throw new RuntimeException(
101                                    "No JSON web service action associated with path " + path +
102                                            " and method " + method + " for /" + servletContextPath);
103                    }
104    
105                    JSONWebServiceActionConfig jsonWebServiceActionConfig =
106                            _jsonWebServiceActionConfigs.get(jsonWebServiceActionConfigIndex);
107    
108                    return new JSONWebServiceActionImpl(
109                            jsonWebServiceActionConfig, jsonWebServiceActionParameters);
110            }
111    
112            public JSONWebServiceActionMapping getJSONWebServiceActionMapping(
113                    String signature) {
114    
115                    for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
116                                    _jsonWebServiceActionConfigs) {
117    
118                            if (signature.equals(jsonWebServiceActionConfig.getSignature())) {
119                                    return jsonWebServiceActionConfig;
120                            }
121                    }
122    
123                    return null;
124            }
125    
126            public List<JSONWebServiceActionMapping> getJSONWebServiceActionMappings(
127                    String servletContextPath) {
128    
129                    List<JSONWebServiceActionMapping> jsonWebServiceActionMappings =
130                            new ArrayList<JSONWebServiceActionMapping>(
131                                    _jsonWebServiceActionConfigs.size());
132    
133                    for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
134                                    _jsonWebServiceActionConfigs) {
135    
136                            String jsonWebServiceServletContextPath =
137                                    jsonWebServiceActionConfig.getServletContextPath();
138    
139                            if (servletContextPath.equals(jsonWebServiceServletContextPath)) {
140                                    jsonWebServiceActionMappings.add(jsonWebServiceActionConfig);
141                            }
142                    }
143    
144                    return jsonWebServiceActionMappings;
145            }
146    
147            public void registerJSONWebServiceAction(
148                    String servletContextPath, Class<?> actionClass, Method actionMethod,
149                    String path, String method) {
150    
151                    JSONWebServiceActionConfig jsonWebServiceActionConfig =
152                            new JSONWebServiceActionConfig(
153                                    servletContextPath, actionClass, actionMethod, path, method);
154    
155                    _jsonWebServiceActionConfigs.add(jsonWebServiceActionConfig);
156            }
157    
158            public int unregisterJSONWebServiceActions(String servletContextPath) {
159                    int count = 0;
160    
161                    Iterator<JSONWebServiceActionConfig> itr =
162                            _jsonWebServiceActionConfigs.iterator();
163    
164                    while (itr.hasNext()) {
165                            JSONWebServiceActionConfig jsonWebServiceActionConfig = itr.next();
166    
167                            if (servletContextPath.equals(
168                                    jsonWebServiceActionConfig.getServletContextPath())) {
169    
170                                    itr.remove();
171    
172                                    count++;
173                            }
174                    }
175    
176                    return count;
177            }
178    
179            private int _countMatchedElements(
180                    String[] parameterNames, MethodParameter[] methodParameters) {
181    
182                    int matched = 0;
183    
184                    for (MethodParameter methodParameter : methodParameters) {
185                            String methodParameterName = methodParameter.getName();
186    
187                            methodParameterName = CamelCaseUtil.normalizeCamelCase(
188                                    methodParameterName);
189    
190                            for (String parameterName : parameterNames) {
191                                    if (parameterName.equals(methodParameterName)) {
192                                            matched++;
193    
194                                            break;
195                                    }
196                            }
197                    }
198    
199                    return matched;
200            }
201    
202            private int _getJSONWebServiceActionConfigIndex(
203                    String servletContextPath, String path, String method,
204                    String[] parameterNames) {
205    
206                    int hint = -1;
207    
208                    int dotIndex = path.indexOf(CharPool.PERIOD);
209    
210                    if (dotIndex != -1) {
211                            hint = GetterUtil.getInteger(path.substring(dotIndex + 1));
212    
213                            path = path.substring(0, dotIndex);
214                    }
215    
216                    path = servletContextPath + path;
217    
218                    int firstIndex = _pathBinarySearch.findFirst(path);
219    
220                    if (firstIndex < 0) {
221                            return -1;
222                    }
223    
224                    int lastIndex = _pathBinarySearch.findLast(path, firstIndex);
225    
226                    if (lastIndex < 0) {
227                            lastIndex = firstIndex;
228                    }
229    
230                    int index = -1;
231    
232                    int max = -1;
233    
234                    for (int i = firstIndex; i <= lastIndex; i++) {
235                            JSONWebServiceActionConfig jsonWebServiceActionConfig
236                                    = _jsonWebServiceActionConfigs.get(i);
237    
238                            String jsonWebServiceActionConfigMethod =
239                                    jsonWebServiceActionConfig.getMethod();
240    
241                            if (PropsValues.JSONWS_WEB_SERVICE_STRICT_HTTP_METHOD &&
242                                    (method != null)) {
243    
244                                    if ((jsonWebServiceActionConfigMethod != null) &&
245                                            !jsonWebServiceActionConfigMethod.equals(method)) {
246    
247                                            continue;
248                                    }
249                            }
250    
251                            MethodParameter[] jsonWebServiceActionConfigMethodParameters =
252                                    jsonWebServiceActionConfig.getMethodParameters();
253    
254                            int methodParametersCount =
255                                    jsonWebServiceActionConfigMethodParameters.length;
256    
257                            if ((hint != -1) && (methodParametersCount != hint)) {
258                                    continue;
259                            }
260    
261                            int count = _countMatchedElements(
262                                    parameterNames, jsonWebServiceActionConfigMethodParameters);
263    
264                            if (count > max) {
265                                    if ((hint != -1) || (count >= methodParametersCount)) {
266                                            max = count;
267    
268                                            index = i;
269                                    }
270                            }
271                    }
272    
273                    return index;
274            }
275    
276            private int _getPathParametersIndex(String path) {
277                    int index = path.indexOf(CharPool.SLASH, 1);
278    
279                    if (index != -1) {
280                            index = path.indexOf(CharPool.SLASH, index + 1);
281                    }
282    
283                    return index;
284            }
285    
286            private SortedArrayList<JSONWebServiceActionConfig>
287                    _jsonWebServiceActionConfigs =
288                            new SortedArrayList<JSONWebServiceActionConfig>();
289            private BinarySearch<String> _pathBinarySearch = new PathBinarySearch();
290    
291            private class PathBinarySearch extends BinarySearch<String> {
292    
293                    @Override
294                    protected int compare(int index, String element) {
295                            JSONWebServiceActionConfig jsonWebServiceActionConfig =
296                                    _jsonWebServiceActionConfigs.get(index);
297    
298                            String fullPath = jsonWebServiceActionConfig.getFullPath();
299    
300                            return fullPath.compareTo(element);
301                    }
302    
303                    @Override
304                    protected int getLastIndex() {
305                            return _jsonWebServiceActionConfigs.size() - 1;
306                    }
307    
308            }
309    
310    }