001
014
015 package com.liferay.portal.jsonwebservice;
016
017 import com.liferay.portal.kernel.bean.BeanLocator;
018 import com.liferay.portal.kernel.bean.PortalBeanLocatorUtil;
019 import com.liferay.portal.kernel.bean.PortletBeanLocatorUtil;
020 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceAction;
021 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionMapping;
022 import com.liferay.portal.kernel.jsonwebservice.JSONWebServiceActionsManager;
023 import com.liferay.portal.kernel.log.Log;
024 import com.liferay.portal.kernel.log.LogFactoryUtil;
025 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
026 import com.liferay.portal.kernel.servlet.HttpMethods;
027 import com.liferay.portal.kernel.util.ArrayUtil;
028 import com.liferay.portal.kernel.util.BinarySearch;
029 import com.liferay.portal.kernel.util.CamelCaseUtil;
030 import com.liferay.portal.kernel.util.CharPool;
031 import com.liferay.portal.kernel.util.ContextPathUtil;
032 import com.liferay.portal.kernel.util.GetterUtil;
033 import com.liferay.portal.kernel.util.MethodParameter;
034 import com.liferay.portal.kernel.util.SortedArrayList;
035 import com.liferay.portal.kernel.util.StringPool;
036 import com.liferay.portal.spring.context.PortalContextLoaderListener;
037 import com.liferay.portal.util.PortalUtil;
038 import com.liferay.portal.util.PropsValues;
039
040 import java.lang.reflect.Method;
041
042 import java.util.ArrayList;
043 import java.util.Iterator;
044 import java.util.List;
045 import java.util.Map;
046 import java.util.Set;
047 import java.util.TreeSet;
048
049 import javax.servlet.ServletContext;
050 import javax.servlet.http.HttpServletRequest;
051 import javax.servlet.http.HttpSession;
052
053
056 @DoPrivileged
057 public class JSONWebServiceActionsManagerImpl
058 implements JSONWebServiceActionsManager {
059
060 @Override
061 public Set<String> getContextPaths() {
062 Set<String> contextPaths = new TreeSet<String>();
063
064 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
065 _jsonWebServiceActionConfigs) {
066
067 String contextPath = jsonWebServiceActionConfig.getContextPath();
068
069 contextPaths.add(contextPath);
070 }
071
072 return contextPaths;
073 }
074
075 @Override
076 public JSONWebServiceAction getJSONWebServiceAction(
077 HttpServletRequest request) {
078
079 String path = GetterUtil.getString(request.getPathInfo());
080
081 String method = GetterUtil.getString(request.getMethod());
082
083 String parameterPath = null;
084
085 JSONRPCRequest jsonRPCRequest = null;
086
087 int parameterPathIndex = _getParameterPathIndex(path);
088
089 if (parameterPathIndex != -1) {
090 parameterPath = path.substring(parameterPathIndex);
091
092 path = path.substring(0, parameterPathIndex);
093 }
094 else {
095 if (method.equals(HttpMethods.POST) &&
096 !PortalUtil.isMultipartRequest(request)) {
097
098 jsonRPCRequest = JSONRPCRequest.detectJSONRPCRequest(request);
099
100 if (jsonRPCRequest != null) {
101 path += StringPool.SLASH + jsonRPCRequest.getMethod();
102
103 method = null;
104 }
105 }
106 }
107
108 JSONWebServiceActionParameters jsonWebServiceActionParameters =
109 new JSONWebServiceActionParameters();
110
111 jsonWebServiceActionParameters.collectAll(
112 request, parameterPath, jsonRPCRequest, null);
113
114 String[] paths = _resolvePaths(request, path);
115
116 String contextPath = paths[0];
117
118 path = paths[1];
119
120 if (_log.isDebugEnabled()) {
121 _log.debug(
122 "Request JSON web service action with path " + path +
123 " and method " + method + " for /" + contextPath);
124 }
125
126 int jsonWebServiceActionConfigIndex =
127 _getJSONWebServiceActionConfigIndex(
128 contextPath, path, method,
129 jsonWebServiceActionParameters.getParameterNames());
130
131 if (jsonWebServiceActionConfigIndex == -1) {
132 throw new RuntimeException(
133 "No JSON web service action associated with path " + path +
134 " and method " + method + " for /" + contextPath);
135 }
136
137 JSONWebServiceActionConfig jsonWebServiceActionConfig =
138 _jsonWebServiceActionConfigs.get(jsonWebServiceActionConfigIndex);
139
140 return new JSONWebServiceActionImpl(
141 jsonWebServiceActionConfig, jsonWebServiceActionParameters);
142 }
143
144 @Override
145 public JSONWebServiceAction getJSONWebServiceAction(
146 HttpServletRequest request, String path, String method,
147 Map<String, Object> parameterMap) {
148
149 JSONWebServiceActionParameters jsonWebServiceActionParameters =
150 new JSONWebServiceActionParameters();
151
152 jsonWebServiceActionParameters.collectAll(
153 request, null, null, parameterMap);
154
155 String[] parameterNames =
156 jsonWebServiceActionParameters.getParameterNames();
157
158 String[] paths = _resolvePaths(request, path);
159
160 String contextPath = paths[0];
161
162 path = paths[1];
163
164 if (_log.isDebugEnabled()) {
165 _log.debug(
166 "Request JSON web service action with path " + path +
167 " and method " + method + " for /" + contextPath);
168 }
169
170 int jsonWebServiceActionConfigIndex =
171 _getJSONWebServiceActionConfigIndex(
172 contextPath, path, method, parameterNames);
173
174 if (jsonWebServiceActionConfigIndex == -1) {
175 throw new RuntimeException(
176 "No JSON web service action with path " + path +
177 " and method " + method + " for /" + contextPath);
178 }
179
180 JSONWebServiceActionConfig jsonWebServiceActionConfig =
181 _jsonWebServiceActionConfigs.get(jsonWebServiceActionConfigIndex);
182
183 return new JSONWebServiceActionImpl(
184 jsonWebServiceActionConfig, jsonWebServiceActionParameters);
185 }
186
187 @Override
188 public JSONWebServiceActionMapping getJSONWebServiceActionMapping(
189 String signature) {
190
191 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
192 _jsonWebServiceActionConfigs) {
193
194 if (signature.equals(jsonWebServiceActionConfig.getSignature())) {
195 return jsonWebServiceActionConfig;
196 }
197 }
198
199 return null;
200 }
201
202 @Override
203 public List<JSONWebServiceActionMapping> getJSONWebServiceActionMappings(
204 String contextPath) {
205
206 List<JSONWebServiceActionMapping> jsonWebServiceActionMappings =
207 new ArrayList<JSONWebServiceActionMapping>(
208 _jsonWebServiceActionConfigs.size());
209
210 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
211 _jsonWebServiceActionConfigs) {
212
213 String jsonWebServiceContextPath =
214 jsonWebServiceActionConfig.getContextPath();
215
216 if (contextPath.equals(jsonWebServiceContextPath)) {
217 jsonWebServiceActionMappings.add(jsonWebServiceActionConfig);
218 }
219 }
220
221 return jsonWebServiceActionMappings;
222 }
223
224 @Override
225 public int getJSONWebServiceActionsCount(String contextPath) {
226 int count = 0;
227
228 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
229 _jsonWebServiceActionConfigs) {
230
231 if (contextPath.equals(
232 jsonWebServiceActionConfig.getContextPath())) {
233
234 count++;
235 }
236 }
237
238 return count;
239 }
240
241 @Override
242 public void registerJSONWebServiceAction(
243 String contextPath, Class<?> actionClass, Method actionMethod,
244 String path, String method) {
245
246 JSONWebServiceActionConfig jsonWebServiceActionConfig =
247 new JSONWebServiceActionConfig(
248 contextPath, actionClass, actionMethod, path, method);
249
250 if (_jsonWebServiceActionConfigs.contains(jsonWebServiceActionConfig)) {
251 if (_log.isDebugEnabled()) {
252 _log.debug(
253 "A JSON web service action is already registered at " +
254 path);
255 }
256
257 return;
258 }
259
260 _jsonWebServiceActionConfigs.add(jsonWebServiceActionConfig);
261 }
262
263 @Override
264 public void registerJSONWebServiceAction(
265 String contextPath, Object actionObject, Class<?> actionClass,
266 Method actionMethod, String path, String method) {
267
268 JSONWebServiceActionConfig jsonWebServiceActionConfig =
269 new JSONWebServiceActionConfig(
270 contextPath, actionObject, actionClass, actionMethod, path,
271 method);
272
273 if (_jsonWebServiceActionConfigs.contains(jsonWebServiceActionConfig)) {
274 if (_log.isWarnEnabled()) {
275 _log.warn(
276 "A JSON web service action is already registered at " +
277 path);
278 }
279
280 return;
281 }
282
283 _jsonWebServiceActionConfigs.add(jsonWebServiceActionConfig);
284 }
285
286 @Override
287 public int registerServletContext(ServletContext servletContext) {
288 String contextPath = ContextPathUtil.getContextPath(servletContext);
289
290 return registerServletContext(contextPath);
291 }
292
293 @Override
294 public int registerServletContext(String contextPath) {
295 BeanLocator beanLocator = null;
296
297 if (contextPath.equals(
298 PortalContextLoaderListener.getPortalServletContextPath()) ||
299 contextPath.isEmpty()) {
300
301 beanLocator = PortalBeanLocatorUtil.getBeanLocator();
302 }
303 else {
304 String contextName = contextPath;
305
306 if (contextName.startsWith(StringPool.SLASH)) {
307 contextName = contextName.substring(1);
308 }
309
310 beanLocator = PortletBeanLocatorUtil.getBeanLocator(contextName);
311 }
312
313 if (beanLocator == null) {
314 if (_log.isInfoEnabled()) {
315 _log.info("Bean locator not available for " + contextPath);
316 }
317
318 return -1;
319 }
320
321 JSONWebServiceRegistrator jsonWebServiceRegistrator =
322 new JSONWebServiceRegistrator();
323
324 jsonWebServiceRegistrator.processAllBeans(contextPath, beanLocator);
325
326 int count = getJSONWebServiceActionsCount(contextPath);
327
328 if (_log.isInfoEnabled()) {
329 _log.info("Configured " + count + " actions for " + contextPath);
330 }
331
332 return count;
333 }
334
335 @Override
336 public int unregisterJSONWebServiceActions(Object actionObject) {
337 int count = 0;
338
339 Iterator<JSONWebServiceActionConfig> iterator =
340 _jsonWebServiceActionConfigs.iterator();
341
342 while (iterator.hasNext()) {
343 JSONWebServiceActionConfig jsonWebServiceActionConfig =
344 iterator.next();
345
346 if (actionObject.equals(
347 jsonWebServiceActionConfig.getActionObject())) {
348
349 iterator.remove();
350
351 count++;
352 }
353 }
354
355 return count;
356 }
357
358 @Override
359 public int unregisterJSONWebServiceActions(String contextPath) {
360 int count = 0;
361
362 Iterator<JSONWebServiceActionConfig> iterator =
363 _jsonWebServiceActionConfigs.iterator();
364
365 while (iterator.hasNext()) {
366 JSONWebServiceActionConfig jsonWebServiceActionConfig =
367 iterator.next();
368
369 if (contextPath.equals(
370 jsonWebServiceActionConfig.getContextPath())) {
371
372 iterator.remove();
373
374 count++;
375 }
376 }
377
378 return count;
379 }
380
381 @Override
382 public int unregisterServletContext(ServletContext servletContext) {
383 String contextPath = ContextPathUtil.getContextPath(servletContext);
384
385 return unregisterJSONWebServiceActions(contextPath);
386 }
387
388 private int _countMatchedElements(
389 String[] parameterNames, MethodParameter[] methodParameters) {
390
391 int matched = 0;
392
393 for (MethodParameter methodParameter : methodParameters) {
394 String methodParameterName = methodParameter.getName();
395
396 methodParameterName = CamelCaseUtil.normalizeCamelCase(
397 methodParameterName);
398
399 if (ArrayUtil.contains(parameterNames, methodParameterName)) {
400 matched++;
401 }
402 }
403
404 return matched;
405 }
406
407 private int _getJSONWebServiceActionConfigIndex(
408 String contextPath, String path, String method,
409 String[] parameterNames) {
410
411 int hint = -1;
412
413 int dotIndex = path.indexOf(CharPool.PERIOD);
414
415 if (dotIndex != -1) {
416 hint = GetterUtil.getInteger(path.substring(dotIndex + 1));
417
418 path = path.substring(0, dotIndex);
419 }
420
421 path = contextPath + path;
422
423 int firstIndex = _pathBinarySearch.findFirst(path);
424
425 if (firstIndex < 0) {
426 if (_log.isDebugEnabled()) {
427 _log.debug(
428 "Unable to find JSON web service actions with path " +
429 path + " for /" + contextPath);
430 }
431
432 return -1;
433 }
434
435 int lastIndex = _pathBinarySearch.findLast(path, firstIndex);
436
437 if (lastIndex < 0) {
438 lastIndex = firstIndex;
439 }
440
441 int index = -1;
442
443 int max = -1;
444
445 if (_log.isDebugEnabled()) {
446 int total = lastIndex - firstIndex + 1;
447
448 _log.debug(
449 "Found " + total + " JSON web service actions with path " +
450 path + " in for /" + contextPath);
451 }
452
453 for (int i = firstIndex; i <= lastIndex; i++) {
454 JSONWebServiceActionConfig jsonWebServiceActionConfig =
455 _jsonWebServiceActionConfigs.get(i);
456
457 String jsonWebServiceActionConfigMethod =
458 jsonWebServiceActionConfig.getMethod();
459
460 if (PropsValues.JSONWS_WEB_SERVICE_STRICT_HTTP_METHOD &&
461 (method != null)) {
462
463 if ((jsonWebServiceActionConfigMethod != null) &&
464 !jsonWebServiceActionConfigMethod.equals(method)) {
465
466 continue;
467 }
468 }
469
470 MethodParameter[] jsonWebServiceActionConfigMethodParameters =
471 jsonWebServiceActionConfig.getMethodParameters();
472
473 int methodParametersCount =
474 jsonWebServiceActionConfigMethodParameters.length;
475
476 if ((hint != -1) && (methodParametersCount != hint)) {
477 continue;
478 }
479
480 int count = _countMatchedElements(
481 parameterNames, jsonWebServiceActionConfigMethodParameters);
482
483 if (count > max) {
484 if ((hint != -1) || (count >= methodParametersCount)) {
485 max = count;
486
487 index = i;
488 }
489 }
490 }
491
492 if (_log.isDebugEnabled()) {
493 if (index == -1) {
494 _log.debug(
495 "Unable to match parameters to a JSON web service " +
496 "action with path " + path + " for /" +
497 contextPath);
498 }
499 else {
500 _log.debug(
501 "Matched parameters to a JSON web service action with " +
502 "path " + path + " for /" + contextPath);
503 }
504 }
505
506 return index;
507 }
508
509 private int _getParameterPathIndex(String path) {
510 int index = path.indexOf(CharPool.SLASH, 1);
511
512 if (index != -1) {
513 index = path.indexOf(CharPool.SLASH, index + 1);
514 }
515
516 return index;
517 }
518
519 private String[] _resolvePaths(HttpServletRequest request, String path) {
520 String contextPath = null;
521
522 int index = path.indexOf(CharPool.FORWARD_SLASH, 1);
523
524 if (index != -1) {
525 index = path.lastIndexOf(CharPool.PERIOD, index);
526
527 if (index != -1) {
528 contextPath = path.substring(0, index);
529
530 path = CharPool.FORWARD_SLASH + path.substring(index + 1);
531 }
532 }
533
534 if (contextPath == null) {
535 HttpSession session = request.getSession();
536
537 ServletContext servletContext = session.getServletContext();
538
539 contextPath = ContextPathUtil.getContextPath(servletContext);
540 }
541
542 return new String[] {contextPath, path};
543 }
544
545 private static Log _log = LogFactoryUtil.getLog(
546 JSONWebServiceActionsManagerImpl.class);
547
548 private SortedArrayList<JSONWebServiceActionConfig>
549 _jsonWebServiceActionConfigs =
550 new SortedArrayList<JSONWebServiceActionConfig>();
551 private BinarySearch<String> _pathBinarySearch = new PathBinarySearch();
552
553 private class PathBinarySearch extends BinarySearch<String> {
554
555 @Override
556 protected int compare(int index, String element) {
557 JSONWebServiceActionConfig jsonWebServiceActionConfig =
558 _jsonWebServiceActionConfigs.get(index);
559
560 String fullPath = jsonWebServiceActionConfig.getFullPath();
561
562 return fullPath.compareTo(element);
563 }
564
565 @Override
566 protected int getLastIndex() {
567 return _jsonWebServiceActionConfigs.size() - 1;
568 }
569
570 }
571
572 }