001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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.GetterUtil;
024    import com.liferay.portal.kernel.util.MethodParameter;
025    import com.liferay.portal.kernel.util.SortedArrayList;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.util.PortalUtil;
028    
029    import java.lang.reflect.Method;
030    
031    import java.util.ArrayList;
032    import java.util.Iterator;
033    import java.util.List;
034    
035    import javax.servlet.http.HttpServletRequest;
036    
037    /**
038     * @author Igor Spasic
039     */
040    public class JSONWebServiceActionsManagerImpl
041            implements JSONWebServiceActionsManager {
042    
043            public JSONWebServiceAction getJSONWebServiceAction(
044                    HttpServletRequest request) {
045    
046                    String path = GetterUtil.getString(request.getPathInfo());
047    
048                    String method = GetterUtil.getString(request.getMethod());
049    
050                    String pathParameters = null;
051    
052                    JSONRPCRequest jsonRpcRequest = null;
053    
054                    int pathParametersIndex = _getPathParametersIndex(path);
055    
056                    if (pathParametersIndex != -1) {
057                            pathParameters = path.substring(pathParametersIndex);
058    
059                            path = path.substring(0, pathParametersIndex);
060                    }
061                    else {
062                            if (method.equals(HttpMethods.POST) &&
063                                    !PortalUtil.isMultipartRequest(request)) {
064    
065                                    jsonRpcRequest = JSONRPCRequest.detectJSONRPCRequest(request);
066    
067                                    if (jsonRpcRequest != null) {
068                                            path += StringPool.SLASH + jsonRpcRequest.getMethod();
069    
070                                            method = null;
071                                    }
072                            }
073                    }
074    
075                    JSONWebServiceActionParameters jsonWebServiceActionParameters =
076                            new JSONWebServiceActionParameters();
077    
078                    jsonWebServiceActionParameters.collectAll(
079                            request, pathParameters, jsonRpcRequest);
080    
081                    String[] parameterNames =
082                            jsonWebServiceActionParameters.getParameterNames();
083    
084                    int jsonWebServiceActionConfigIndex =
085                            _getJSONWebServiceActionConfigIndex(path, method, parameterNames);
086    
087                    if (jsonWebServiceActionConfigIndex == -1) {
088                            throw new RuntimeException(
089                                    "No JSON web service action associated with path " + path +
090                                            " and method " + method);
091                    }
092    
093                    JSONWebServiceActionConfig jsonWebServiceActionConfig =
094                            _jsonWebServiceActionConfigs.get(jsonWebServiceActionConfigIndex);
095    
096                    return new JSONWebServiceActionImpl(
097                            jsonWebServiceActionConfig, jsonWebServiceActionParameters);
098            }
099    
100            public JSONWebServiceActionMapping getJSONWebServiceActionMapping(
101                    String signature) {
102    
103                    for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
104                                    _jsonWebServiceActionConfigs) {
105    
106                            if (signature.equals(jsonWebServiceActionConfig.getSignature())) {
107                                    return jsonWebServiceActionConfig;
108                            }
109                    }
110    
111                    return null;
112            }
113    
114            public List<JSONWebServiceActionMapping> getJSONWebServiceActionMappings() {
115                    List<JSONWebServiceActionMapping> jsonWebServiceActionMappings =
116                            new ArrayList<JSONWebServiceActionMapping>(
117                                    _jsonWebServiceActionConfigs.size());
118    
119                    for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
120                                    _jsonWebServiceActionConfigs) {
121    
122                            jsonWebServiceActionMappings.add(jsonWebServiceActionConfig);
123                    }
124    
125                    return jsonWebServiceActionMappings;
126            }
127    
128            public void registerJSONWebServiceAction(
129                    String servletContextName, Class<?> actionClass, Method actionMethod,
130                    String path, String method) {
131    
132                    JSONWebServiceActionConfig jsonWebServiceActionConfig =
133                            new JSONWebServiceActionConfig(
134                                    servletContextName, actionClass, actionMethod, path, method);
135    
136                    _jsonWebServiceActionConfigs.add(jsonWebServiceActionConfig);
137            }
138    
139            public int unregisterJSONWebServiceActions(String servletContextName) {
140                    if (servletContextName == null) {
141                            return 0;
142                    }
143    
144                    int count = 0;
145    
146                    Iterator<JSONWebServiceActionConfig> itr =
147                            _jsonWebServiceActionConfigs.iterator();
148    
149                    while (itr.hasNext()) {
150                            JSONWebServiceActionConfig jsonWebServiceActionConfig = itr.next();
151    
152                            if (servletContextName.equals(
153                                            jsonWebServiceActionConfig.getServletContextName())) {
154    
155                                    itr.remove();
156    
157                                    count++;
158                            }
159                    }
160    
161                    return count;
162            }
163    
164            private int _countMatchedElements(
165                    String[] parameterNames, MethodParameter[] methodParameters) {
166    
167                    int matched = 0;
168    
169                    for (String parameterName : parameterNames) {
170                            for (MethodParameter methodParameter : methodParameters) {
171                                    if (parameterName.equals(methodParameter.getName())) {
172                                            matched++;
173    
174                                            break;
175                                    }
176                            }
177                    }
178    
179                    return matched;
180            }
181    
182            private int _getJSONWebServiceActionConfigIndex(
183                    String path, String method, String[] parameterNames) {
184    
185                    int hint = -1;
186    
187                    int dotIndex = path.indexOf(CharPool.PERIOD);
188    
189                    if (dotIndex != -1) {
190                            hint = GetterUtil.getInteger(path.substring(dotIndex + 1));
191    
192                            path = path.substring(0, dotIndex);
193                    }
194    
195                    int firstIndex = _pathBinarySearch.findFirst(path);
196    
197                    if (firstIndex < 0) {
198                            return -1;
199                    }
200    
201                    int lastIndex = _pathBinarySearch.findLast(path, firstIndex);
202    
203                    if (lastIndex < 0) {
204                            lastIndex = firstIndex;
205                    }
206    
207                    int index = -1;
208    
209                    int max = -1;
210    
211                    for (int i = firstIndex; i <= lastIndex; i++) {
212                            JSONWebServiceActionConfig jsonWebServiceActionConfig
213                                    = _jsonWebServiceActionConfigs.get(i);
214    
215                            String jsonWebServiceActionConfigMethod =
216                                    jsonWebServiceActionConfig.getMethod();
217    
218                            if (method != null) {
219                                    if ((jsonWebServiceActionConfigMethod != null) &&
220                                            !jsonWebServiceActionConfigMethod.equals(method)) {
221    
222                                            continue;
223                                    }
224                            }
225    
226                            MethodParameter[] jsonWebServiceActionConfigMethodParameters =
227                                    jsonWebServiceActionConfig.getMethodParameters();
228    
229                            int methodParametersCount =
230                                    jsonWebServiceActionConfigMethodParameters.length;
231    
232                            if ((hint != -1) && (methodParametersCount != hint)) {
233                                    continue;
234                            }
235    
236                            int count = _countMatchedElements(
237                                    parameterNames, jsonWebServiceActionConfigMethodParameters);
238    
239                            if (count > max) {
240                                    if ((hint != -1) || (count >= methodParametersCount)) {
241                                            max = count;
242    
243                                            index = i;
244                                    }
245                            }
246                    }
247    
248                    return index;
249            }
250    
251            private int _getPathParametersIndex(String path) {
252                    int index = path.indexOf(CharPool.SLASH, 1);
253    
254                    if (index != -1) {
255                            index = path.indexOf(CharPool.SLASH, index + 1);
256                    }
257    
258                    return index;
259            }
260    
261            private SortedArrayList<JSONWebServiceActionConfig>
262                    _jsonWebServiceActionConfigs =
263                            new SortedArrayList<JSONWebServiceActionConfig>();
264            private BinarySearch<String> _pathBinarySearch  = new PathBinarySearch();
265    
266            private class PathBinarySearch extends BinarySearch<String> {
267    
268                    @Override
269                    protected int compare(int index, String element) {
270                            JSONWebServiceActionConfig jsonWebServiceActionConfig =
271                                    _jsonWebServiceActionConfigs.get(index);
272    
273                            String path = jsonWebServiceActionConfig.getPath();
274    
275                            return path.compareTo(element);
276                    }
277    
278                    @Override
279                    protected int getLastIndex() {
280                            return _jsonWebServiceActionConfigs.size() - 1;
281                    }
282    
283            }
284    
285    }