001
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.log.Log;
021 import com.liferay.portal.kernel.log.LogFactoryUtil;
022 import com.liferay.portal.kernel.servlet.HttpMethods;
023 import com.liferay.portal.kernel.util.ArrayUtil;
024 import com.liferay.portal.kernel.util.BinarySearch;
025 import com.liferay.portal.kernel.util.CamelCaseUtil;
026 import com.liferay.portal.kernel.util.CharPool;
027 import com.liferay.portal.kernel.util.ContextPathUtil;
028 import com.liferay.portal.kernel.util.GetterUtil;
029 import com.liferay.portal.kernel.util.MethodParameter;
030 import com.liferay.portal.kernel.util.SortedArrayList;
031 import com.liferay.portal.kernel.util.StringPool;
032 import com.liferay.portal.util.PortalUtil;
033 import com.liferay.portal.util.PropsValues;
034
035 import java.lang.reflect.Method;
036
037 import java.util.ArrayList;
038 import java.util.Iterator;
039 import java.util.List;
040 import java.util.Map;
041 import java.util.Set;
042 import java.util.TreeSet;
043
044 import javax.servlet.ServletContext;
045 import javax.servlet.http.HttpServletRequest;
046 import javax.servlet.http.HttpSession;
047
048
051 public class JSONWebServiceActionsManagerImpl
052 implements JSONWebServiceActionsManager {
053
054 public Set<String> getContextPaths() {
055 Set<String> contextPaths = new TreeSet<String>();
056
057 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
058 _jsonWebServiceActionConfigs) {
059
060 String contextPath = jsonWebServiceActionConfig.getContextPath();
061
062 contextPaths.add(contextPath);
063 }
064
065 return contextPaths;
066 }
067
068 public JSONWebServiceAction getJSONWebServiceAction(
069 HttpServletRequest request) {
070
071 String path = GetterUtil.getString(request.getPathInfo());
072
073 String method = GetterUtil.getString(request.getMethod());
074
075 String parameterPath = null;
076
077 JSONRPCRequest jsonRPCRequest = null;
078
079 int parameterPathIndex = _getParameterPathIndex(path);
080
081 if (parameterPathIndex != -1) {
082 parameterPath = path.substring(parameterPathIndex);
083
084 path = path.substring(0, parameterPathIndex);
085 }
086 else {
087 if (method.equals(HttpMethods.POST) &&
088 !PortalUtil.isMultipartRequest(request)) {
089
090 jsonRPCRequest = JSONRPCRequest.detectJSONRPCRequest(request);
091
092 if (jsonRPCRequest != null) {
093 path += StringPool.SLASH + jsonRPCRequest.getMethod();
094
095 method = null;
096 }
097 }
098 }
099
100 JSONWebServiceActionParameters jsonWebServiceActionParameters =
101 new JSONWebServiceActionParameters();
102
103 jsonWebServiceActionParameters.collectAll(
104 request, parameterPath, jsonRPCRequest, null);
105
106 String[] paths = _resolvePaths(request, path);
107
108 String servletContextPath = paths[0];
109
110 path = paths[1];
111
112 if (_log.isDebugEnabled()) {
113 _log.debug(
114 "Request JSON web service action with path " + path +
115 " and method " + method + " for /" + servletContextPath);
116 }
117
118 int jsonWebServiceActionConfigIndex =
119 _getJSONWebServiceActionConfigIndex(
120 servletContextPath, path, method,
121 jsonWebServiceActionParameters.getParameterNames());
122
123 if (jsonWebServiceActionConfigIndex == -1) {
124 throw new RuntimeException(
125 "No JSON web service action associated with path " + path +
126 " and method " + method + " for /" + servletContextPath);
127 }
128
129 JSONWebServiceActionConfig jsonWebServiceActionConfig =
130 _jsonWebServiceActionConfigs.get(jsonWebServiceActionConfigIndex);
131
132 return new JSONWebServiceActionImpl(
133 jsonWebServiceActionConfig, jsonWebServiceActionParameters);
134 }
135
136 public JSONWebServiceAction getJSONWebServiceAction(
137 HttpServletRequest request, String path, String method,
138 Map<String, Object> parameterMap) {
139
140 JSONWebServiceActionParameters jsonWebServiceActionParameters =
141 new JSONWebServiceActionParameters();
142
143 jsonWebServiceActionParameters.collectAll(
144 request, null, null, parameterMap);
145
146 String[] parameterNames =
147 jsonWebServiceActionParameters.getParameterNames();
148
149 String[] paths = _resolvePaths(request, path);
150
151 String servletContextPath = paths[0];
152
153 path = paths[1];
154
155 if (_log.isDebugEnabled()) {
156 _log.debug(
157 "Require JSON web service action with path " + path +
158 " and method " + method + " for /" + servletContextPath);
159 }
160
161 int jsonWebServiceActionConfigIndex =
162 _getJSONWebServiceActionConfigIndex(
163 servletContextPath, path, method, parameterNames);
164
165 if (jsonWebServiceActionConfigIndex == -1) {
166 throw new RuntimeException(
167 "No JSON web service action with path " + path +
168 " and method " + method + " for /" + servletContextPath);
169 }
170
171 JSONWebServiceActionConfig jsonWebServiceActionConfig =
172 _jsonWebServiceActionConfigs.get(jsonWebServiceActionConfigIndex);
173
174 return new JSONWebServiceActionImpl(
175 jsonWebServiceActionConfig, jsonWebServiceActionParameters);
176 }
177
178 public JSONWebServiceActionMapping getJSONWebServiceActionMapping(
179 String signature) {
180
181 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
182 _jsonWebServiceActionConfigs) {
183
184 if (signature.equals(jsonWebServiceActionConfig.getSignature())) {
185 return jsonWebServiceActionConfig;
186 }
187 }
188
189 return null;
190 }
191
192 public List<JSONWebServiceActionMapping> getJSONWebServiceActionMappings(
193 String contextPath) {
194
195 List<JSONWebServiceActionMapping> jsonWebServiceActionMappings =
196 new ArrayList<JSONWebServiceActionMapping>(
197 _jsonWebServiceActionConfigs.size());
198
199 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
200 _jsonWebServiceActionConfigs) {
201
202 String jsonWebServiceContextPath =
203 jsonWebServiceActionConfig.getContextPath();
204
205 if (contextPath.equals(jsonWebServiceContextPath)) {
206 jsonWebServiceActionMappings.add(jsonWebServiceActionConfig);
207 }
208 }
209
210 return jsonWebServiceActionMappings;
211 }
212
213 public void registerJSONWebServiceAction(
214 String servletContextPath, Class<?> actionClass, Method actionMethod,
215 String path, String method) {
216
217 JSONWebServiceActionConfig jsonWebServiceActionConfig =
218 new JSONWebServiceActionConfig(
219 servletContextPath, actionClass, actionMethod, path, method);
220
221 if (_jsonWebServiceActionConfigs.contains(jsonWebServiceActionConfig)) {
222 if (_log.isDebugEnabled()) {
223 _log.debug(
224 "A JSON web service action is already registered at " +
225 path);
226 }
227
228 return;
229 }
230
231 _jsonWebServiceActionConfigs.add(jsonWebServiceActionConfig);
232 }
233
234 public int unregisterJSONWebServiceActions(String contextPath) {
235 int count = 0;
236
237 Iterator<JSONWebServiceActionConfig> iterator =
238 _jsonWebServiceActionConfigs.iterator();
239
240 while (iterator.hasNext()) {
241 JSONWebServiceActionConfig jsonWebServiceActionConfig =
242 iterator.next();
243
244 if (contextPath.equals(
245 jsonWebServiceActionConfig.getContextPath())) {
246
247 iterator.remove();
248
249 count++;
250 }
251 }
252
253 return count;
254 }
255
256 private int _countMatchedElements(
257 String[] parameterNames, MethodParameter[] methodParameters) {
258
259 int matched = 0;
260
261 for (MethodParameter methodParameter : methodParameters) {
262 String methodParameterName = methodParameter.getName();
263
264 methodParameterName = CamelCaseUtil.normalizeCamelCase(
265 methodParameterName);
266
267 if (ArrayUtil.contains(parameterNames, methodParameterName)) {
268 matched++;
269 }
270 }
271
272 return matched;
273 }
274
275 private int _getJSONWebServiceActionConfigIndex(
276 String servletContextPath, String path, String method,
277 String[] parameterNames) {
278
279 int hint = -1;
280
281 int dotIndex = path.indexOf(CharPool.PERIOD);
282
283 if (dotIndex != -1) {
284 hint = GetterUtil.getInteger(path.substring(dotIndex + 1));
285
286 path = path.substring(0, dotIndex);
287 }
288
289 path = servletContextPath + path;
290
291 int firstIndex = _pathBinarySearch.findFirst(path);
292
293 if (firstIndex < 0) {
294 if (_log.isDebugEnabled()) {
295 _log.debug(
296 "Unable to find JSON web service actions with path " +
297 path + " for /" + servletContextPath);
298 }
299
300 return -1;
301 }
302
303 int lastIndex = _pathBinarySearch.findLast(path, firstIndex);
304
305 if (lastIndex < 0) {
306 lastIndex = firstIndex;
307 }
308
309 int index = -1;
310
311 int max = -1;
312
313 if (_log.isDebugEnabled()) {
314 int total = lastIndex - firstIndex + 1;
315
316 _log.debug(
317 "Found " + total + " JSON web service actions with path " +
318 path + " in for /" + servletContextPath);
319 }
320
321 for (int i = firstIndex; i <= lastIndex; i++) {
322 JSONWebServiceActionConfig jsonWebServiceActionConfig =
323 _jsonWebServiceActionConfigs.get(i);
324
325 String jsonWebServiceActionConfigMethod =
326 jsonWebServiceActionConfig.getMethod();
327
328 if (PropsValues.JSONWS_WEB_SERVICE_STRICT_HTTP_METHOD &&
329 (method != null)) {
330
331 if ((jsonWebServiceActionConfigMethod != null) &&
332 !jsonWebServiceActionConfigMethod.equals(method)) {
333
334 continue;
335 }
336 }
337
338 MethodParameter[] jsonWebServiceActionConfigMethodParameters =
339 jsonWebServiceActionConfig.getMethodParameters();
340
341 int methodParametersCount =
342 jsonWebServiceActionConfigMethodParameters.length;
343
344 if ((hint != -1) && (methodParametersCount != hint)) {
345 continue;
346 }
347
348 int count = _countMatchedElements(
349 parameterNames, jsonWebServiceActionConfigMethodParameters);
350
351 if (count > max) {
352 if ((hint != -1) || (count >= methodParametersCount)) {
353 max = count;
354
355 index = i;
356 }
357 }
358 }
359
360 if (_log.isDebugEnabled()) {
361 if (index == -1) {
362 _log.debug(
363 "Unable to match parameters to a JSON web service " +
364 "action with path " + path + " for /" +
365 servletContextPath);
366 }
367 else {
368 _log.debug(
369 "Matched parameters to a JSON web service action with " +
370 "path " + path + " for /" + servletContextPath);
371 }
372 }
373
374 return index;
375 }
376
377 private int _getParameterPathIndex(String path) {
378 int index = path.indexOf(CharPool.SLASH, 1);
379
380 if (index != -1) {
381 index = path.indexOf(CharPool.SLASH, index + 1);
382 }
383
384 return index;
385 }
386
387 private String[] _resolvePaths(HttpServletRequest request, String path) {
388 String servletContextPath = null;
389
390 int index = path.indexOf(CharPool.FORWARD_SLASH, 1);
391
392 if (index != -1) {
393 index = path.lastIndexOf(CharPool.PERIOD, index);
394
395 if (index != -1) {
396 servletContextPath = path.substring(0, index);
397
398 path = CharPool.FORWARD_SLASH + path.substring(index + 1);
399 }
400 }
401
402 if (servletContextPath == null) {
403 HttpSession session = request.getSession();
404
405 ServletContext servletContext = session.getServletContext();
406
407 servletContextPath = ContextPathUtil.getContextPath(servletContext);
408 }
409
410 return new String[] {servletContextPath, path};
411 }
412
413 private static Log _log = LogFactoryUtil.getLog(
414 JSONWebServiceActionParameters.class);
415
416 private SortedArrayList<JSONWebServiceActionConfig>
417 _jsonWebServiceActionConfigs =
418 new SortedArrayList<JSONWebServiceActionConfig>();
419 private BinarySearch<String> _pathBinarySearch = new PathBinarySearch();
420
421 private class PathBinarySearch extends BinarySearch<String> {
422
423 @Override
424 protected int compare(int index, String element) {
425 JSONWebServiceActionConfig jsonWebServiceActionConfig =
426 _jsonWebServiceActionConfigs.get(index);
427
428 String fullPath = jsonWebServiceActionConfig.getFullPath();
429
430 return fullPath.compareTo(element);
431 }
432
433 @Override
434 protected int getLastIndex() {
435 return _jsonWebServiceActionConfigs.size() - 1;
436 }
437
438 }
439
440 }