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.jsonwebservice.JSONWebServiceNaming;
024 import com.liferay.portal.kernel.jsonwebservice.NoSuchJSONWebServiceException;
025 import com.liferay.portal.kernel.log.Log;
026 import com.liferay.portal.kernel.log.LogFactoryUtil;
027 import com.liferay.portal.kernel.security.pacl.DoPrivileged;
028 import com.liferay.portal.kernel.servlet.HttpMethods;
029 import com.liferay.portal.kernel.util.BinarySearch;
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.StringBundler;
036 import com.liferay.portal.kernel.util.StringPool;
037 import com.liferay.portal.kernel.util.StringUtil;
038 import com.liferay.portal.kernel.util.Validator;
039 import com.liferay.portal.service.ServiceContextThreadLocal;
040 import com.liferay.portal.spring.context.PortalContextLoaderListener;
041 import com.liferay.portal.util.PortalUtil;
042 import com.liferay.portal.util.PropsValues;
043
044 import java.lang.reflect.Method;
045
046 import java.util.ArrayList;
047 import java.util.Iterator;
048 import java.util.List;
049 import java.util.Map;
050 import java.util.Set;
051 import java.util.TreeSet;
052
053 import javax.servlet.ServletContext;
054 import javax.servlet.http.HttpServletRequest;
055
056
060 @DoPrivileged
061 public class JSONWebServiceActionsManagerImpl
062 implements JSONWebServiceActionsManager {
063
064 @Override
065 public Set<String> getContextNames() {
066 Set<String> contextNames = new TreeSet<String>();
067
068 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
069 _jsonWebServiceActionConfigs) {
070
071 String contextName = jsonWebServiceActionConfig.getContextName();
072
073 contextNames.add(contextName);
074 }
075
076 return contextNames;
077 }
078
079 @Override
080 public JSONWebServiceAction getJSONWebServiceAction(
081 HttpServletRequest request)
082 throws NoSuchJSONWebServiceException {
083
084 String path = GetterUtil.getString(request.getPathInfo());
085
086 String method = GetterUtil.getString(request.getMethod());
087
088 String parameterPath = null;
089
090 JSONRPCRequest jsonRPCRequest = null;
091
092 int parameterPathIndex = _getParameterPathIndex(path);
093
094 if (parameterPathIndex != -1) {
095 parameterPath = path.substring(parameterPathIndex);
096
097 path = path.substring(0, parameterPathIndex);
098 }
099 else {
100 if (method.equals(HttpMethods.POST) &&
101 !PortalUtil.isMultipartRequest(request)) {
102
103 jsonRPCRequest = JSONRPCRequest.detectJSONRPCRequest(request);
104
105 if (jsonRPCRequest != null) {
106 path += StringPool.SLASH + jsonRPCRequest.getMethod();
107
108 method = null;
109 }
110 }
111 }
112
113 JSONWebServiceActionParameters jsonWebServiceActionParameters =
114 new JSONWebServiceActionParameters();
115
116 jsonWebServiceActionParameters.collectAll(
117 request, parameterPath, jsonRPCRequest, null);
118
119 if (jsonWebServiceActionParameters.getServiceContext() != null) {
120 ServiceContextThreadLocal.pushServiceContext(
121 jsonWebServiceActionParameters.getServiceContext());
122 }
123
124 JSONWebServiceActionConfig jsonWebServiceActionConfig =
125 _findJSONWebServiceAction(
126 request, path, method, jsonWebServiceActionParameters);
127
128 return new JSONWebServiceActionImpl(
129 jsonWebServiceActionConfig, jsonWebServiceActionParameters,
130 _jsonWebServiceNaming);
131 }
132
133 @Override
134 public JSONWebServiceAction getJSONWebServiceAction(
135 HttpServletRequest request, String path, String method,
136 Map<String, Object> parameterMap)
137 throws NoSuchJSONWebServiceException {
138
139 JSONWebServiceActionParameters jsonWebServiceActionParameters =
140 new JSONWebServiceActionParameters();
141
142 jsonWebServiceActionParameters.collectAll(
143 request, null, null, parameterMap);
144
145 JSONWebServiceActionConfig jsonWebServiceActionConfig =
146 _findJSONWebServiceAction(
147 request, path, method, jsonWebServiceActionParameters);
148
149 return new JSONWebServiceActionImpl(
150 jsonWebServiceActionConfig, jsonWebServiceActionParameters,
151 _jsonWebServiceNaming);
152 }
153
154 @Override
155 public JSONWebServiceActionMapping getJSONWebServiceActionMapping(
156 String signature) {
157
158 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
159 _jsonWebServiceActionConfigs) {
160
161 if (signature.equals(jsonWebServiceActionConfig.getSignature())) {
162 return jsonWebServiceActionConfig;
163 }
164 }
165
166 return null;
167 }
168
169 @Override
170 public List<JSONWebServiceActionMapping> getJSONWebServiceActionMappings(
171 String contextName) {
172
173 List<JSONWebServiceActionMapping> jsonWebServiceActionMappings =
174 new ArrayList<JSONWebServiceActionMapping>(
175 _jsonWebServiceActionConfigs.size());
176
177 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
178 _jsonWebServiceActionConfigs) {
179
180 if (contextName.equals(
181 jsonWebServiceActionConfig.getContextName())) {
182
183 jsonWebServiceActionMappings.add(jsonWebServiceActionConfig);
184 }
185 }
186
187 return jsonWebServiceActionMappings;
188 }
189
190 @Override
191 public int getJSONWebServiceActionsCount(String contextName) {
192 int count = 0;
193
194
195
196
197 for (int i = 0; i < _jsonWebServiceActionConfigs.size(); i++) {
198 JSONWebServiceActionConfig jsonWebServiceActionConfig =
199 _jsonWebServiceActionConfigs.get(i);
200
201 if (contextName.equals(
202 jsonWebServiceActionConfig.getContextName())) {
203
204 count++;
205 }
206 }
207
208 return count;
209 }
210
211 @Override
212 public JSONWebServiceNaming getJSONWebServiceNaming() {
213 return _jsonWebServiceNaming;
214 }
215
216 @Override
217 public void registerJSONWebServiceAction(
218 String contextName, String contextPath, Class<?> actionClass,
219 Method actionMethod, String path, String method) {
220
221 try {
222 JSONWebServiceActionConfig jsonWebServiceActionConfig =
223 new JSONWebServiceActionConfig(
224 contextName, contextPath, actionClass, actionMethod, path,
225 method);
226
227 if (_jsonWebServiceActionConfigs.contains(
228 jsonWebServiceActionConfig)) {
229
230 if (_log.isDebugEnabled()) {
231 _log.debug(
232 "A JSON web service action is already registered at " +
233 path);
234 }
235
236 return;
237 }
238
239 _jsonWebServiceActionConfigs.add(jsonWebServiceActionConfig);
240 }
241 catch (Exception e) {
242 if (_log.isWarnEnabled()) {
243 StringBundler sb = new StringBundler(14);
244
245 sb.append("Unable to register service method {actionClass=");
246 sb.append(actionClass);
247 sb.append(", actionMethod=");
248 sb.append(actionMethod);
249 sb.append(", contextName=");
250 sb.append(contextName);
251 sb.append(", contextPath=");
252 sb.append(contextPath);
253 sb.append(", method=");
254 sb.append(method);
255 sb.append(", path=");
256 sb.append(path);
257 sb.append("} due to ");
258 sb.append(e.getMessage());
259
260 _log.warn(sb.toString());
261 }
262 }
263 }
264
265 @Override
266 public void registerJSONWebServiceAction(
267 String contextName, String contextPath, Object actionObject,
268 Class<?> actionClass, Method actionMethod, String path, String method) {
269
270 try {
271 JSONWebServiceActionConfig jsonWebServiceActionConfig =
272 new JSONWebServiceActionConfig(
273 contextName, contextPath, actionObject, actionClass,
274 actionMethod, path, method);
275
276 if (_jsonWebServiceActionConfigs.contains(
277 jsonWebServiceActionConfig)) {
278
279 if (_log.isWarnEnabled()) {
280 _log.warn(
281 "A JSON web service action is already registered at " +
282 path);
283 }
284
285 return;
286 }
287
288 _jsonWebServiceActionConfigs.add(jsonWebServiceActionConfig);
289 }
290 catch (Exception e) {
291 StringBundler sb = new StringBundler(17);
292
293 sb.append("Something went wrong attempting to register service ");
294 sb.append("method {contextName=");
295 sb.append(contextName);
296 sb.append(",contextPath=");
297 sb.append(contextPath);
298 sb.append(",actionObject=");
299 sb.append(actionObject);
300 sb.append(",actionClass=");
301 sb.append(actionClass);
302 sb.append(",actionMethod=");
303 sb.append(actionMethod);
304 sb.append(",path=");
305 sb.append(path);
306 sb.append(",method=");
307 sb.append(method);
308 sb.append("} due to ");
309 sb.append(e.getMessage());
310
311 _log.warn(sb.toString());
312 }
313 }
314
315 @Override
316 public int registerService(String contextPath, Object service) {
317 return registerService(StringPool.BLANK, contextPath, service);
318 }
319
320 @Override
321 public int registerService(
322 String contextName, String contextPath, Object service) {
323
324 JSONWebServiceRegistrator jsonWebServiceRegistrator =
325 new JSONWebServiceRegistrator();
326
327 jsonWebServiceRegistrator.processBean(
328 contextName, contextPath, service);
329
330 int count = getJSONWebServiceActionsCount(contextPath);
331
332 if (_log.isInfoEnabled()) {
333 _log.info("Configured " + count + " actions for " + contextPath);
334 }
335
336 return count;
337 }
338
339 @Override
340 public int registerServletContext(ServletContext servletContext) {
341 BeanLocator beanLocator = null;
342
343 String contextName = servletContext.getServletContextName();
344 String contextPath = servletContext.getContextPath();
345
346 if (contextPath.equals(
347 PortalContextLoaderListener.getPortalServletContextPath()) ||
348 contextPath.isEmpty()) {
349
350 beanLocator = PortalBeanLocatorUtil.getBeanLocator();
351 }
352 else {
353 beanLocator = PortletBeanLocatorUtil.getBeanLocator(contextName);
354 }
355
356 if (beanLocator == null) {
357 if (_log.isInfoEnabled()) {
358 _log.info("Bean locator not available for " + contextPath);
359 }
360
361 return -1;
362 }
363
364 JSONWebServiceRegistrator jsonWebServiceRegistrator =
365 new JSONWebServiceRegistrator();
366
367 jsonWebServiceRegistrator.processAllBeans(
368 contextName, contextPath, beanLocator);
369
370 int count = getJSONWebServiceActionsCount(contextPath);
371
372 if (_log.isInfoEnabled()) {
373 _log.info("Configured " + count + " actions for " + contextPath);
374 }
375
376 return count;
377 }
378
379 @Override
380 public int unregisterJSONWebServiceActions(Object actionObject) {
381 int count = 0;
382
383 Iterator<JSONWebServiceActionConfig> iterator =
384 _jsonWebServiceActionConfigs.iterator();
385
386 while (iterator.hasNext()) {
387 JSONWebServiceActionConfig jsonWebServiceActionConfig =
388 iterator.next();
389
390 if (actionObject.equals(
391 jsonWebServiceActionConfig.getActionObject())) {
392
393 iterator.remove();
394
395 count++;
396 }
397 }
398
399 return count;
400 }
401
402 @Override
403 public int unregisterJSONWebServiceActions(String contextPath) {
404 int count = 0;
405
406 Iterator<JSONWebServiceActionConfig> iterator =
407 _jsonWebServiceActionConfigs.iterator();
408
409 while (iterator.hasNext()) {
410 JSONWebServiceActionConfig jsonWebServiceActionConfig =
411 iterator.next();
412
413 if (contextPath.equals(
414 jsonWebServiceActionConfig.getContextPath())) {
415
416 iterator.remove();
417
418 count++;
419 }
420 }
421
422 return count;
423 }
424
425 @Override
426 public int unregisterServletContext(ServletContext servletContext) {
427 String contextPath = ContextPathUtil.getContextPath(servletContext);
428
429 return unregisterJSONWebServiceActions(contextPath);
430 }
431
432 private int _countMatchedParameters(
433 String[] parameterNames, MethodParameter[] methodParameters) {
434
435 int matched = 0;
436
437 for (MethodParameter methodParameter : methodParameters) {
438 String methodParameterName = methodParameter.getName();
439
440 methodParameterName = StringUtil.toLowerCase(methodParameterName);
441
442 for (String parameterName : parameterNames) {
443 if (StringUtil.equalsIgnoreCase(
444 parameterName, methodParameterName)) {
445
446 matched++;
447 }
448 }
449 }
450
451 return matched;
452 }
453
454 private JSONWebServiceActionConfig _findJSONWebServiceAction(
455 HttpServletRequest request, String path, String method,
456 JSONWebServiceActionParameters jsonWebServiceActionParameters)
457 throws NoSuchJSONWebServiceException {
458
459 String[] paths = _resolvePaths(request, path);
460
461 String contextName = paths[0];
462
463 path = paths[1];
464
465 if (_log.isDebugEnabled()) {
466 _log.debug(
467 "Request JSON web service action with path " + path +
468 " and method " + method + " for " + contextName);
469 }
470
471 String[] parameterNames =
472 jsonWebServiceActionParameters.getParameterNames();
473
474 int jsonWebServiceActionConfigIndex =
475 _getJSONWebServiceActionConfigIndex(
476 contextName, path, method, parameterNames);
477
478 if (jsonWebServiceActionConfigIndex == -1) {
479 if (jsonWebServiceActionParameters.includeDefaultParameters()) {
480 parameterNames =
481 jsonWebServiceActionParameters.getParameterNames();
482
483 jsonWebServiceActionConfigIndex =
484 _getJSONWebServiceActionConfigIndex(
485 contextName, path, method, parameterNames);
486 }
487 }
488
489 if (jsonWebServiceActionConfigIndex == -1) {
490 throw new NoSuchJSONWebServiceException(
491 "No JSON web service action with path " + path +
492 " and method " + method + " for " + contextName);
493 }
494
495 JSONWebServiceActionConfig jsonWebServiceActionConfig =
496 _jsonWebServiceActionConfigs.get(jsonWebServiceActionConfigIndex);
497
498 return jsonWebServiceActionConfig;
499 }
500
501 private int _getJSONWebServiceActionConfigIndex(
502 String contextName, String path, String method,
503 String[] parameterNames) {
504
505 int hint = -1;
506
507 int offset = 0;
508
509 if (Validator.isNotNull(contextName)) {
510 String pathPrefix = StringPool.SLASH.concat(contextName).concat(
511 StringPool.PERIOD);
512
513 if (path.startsWith(pathPrefix)) {
514 offset = pathPrefix.length();
515 }
516 }
517
518 int dotIndex = path.indexOf(CharPool.PERIOD, offset);
519
520 if (dotIndex != -1) {
521 hint = GetterUtil.getInteger(path.substring(dotIndex + 1), -1);
522
523 if (hint != -1) {
524 path = path.substring(0, dotIndex);
525 }
526 }
527
528 int firstIndex = _pathBinarySearch.findFirst(path);
529
530 if (firstIndex < 0) {
531 if (_log.isDebugEnabled()) {
532 _log.debug(
533 "Unable to find JSON web service actions with path " +
534 path + " for " + contextName);
535 }
536
537 return -1;
538 }
539
540 int lastIndex = _pathBinarySearch.findLast(path, firstIndex);
541
542 if (lastIndex < 0) {
543 lastIndex = firstIndex;
544 }
545
546 int index = -1;
547
548 int max = -1;
549
550 if (_log.isDebugEnabled()) {
551 int total = lastIndex - firstIndex + 1;
552
553 _log.debug(
554 "Found " + total + " JSON web service actions with path " +
555 path + " in for " + contextName);
556 }
557
558 for (int i = firstIndex; i <= lastIndex; i++) {
559 JSONWebServiceActionConfig jsonWebServiceActionConfig =
560 _jsonWebServiceActionConfigs.get(i);
561
562 String jsonWebServiceActionConfigMethod =
563 jsonWebServiceActionConfig.getMethod();
564
565 if (PropsValues.JSONWS_WEB_SERVICE_STRICT_HTTP_METHOD &&
566 (method != null)) {
567
568 if ((jsonWebServiceActionConfigMethod != null) &&
569 !jsonWebServiceActionConfigMethod.equals(method)) {
570
571 continue;
572 }
573 }
574
575 MethodParameter[] jsonWebServiceActionConfigMethodParameters =
576 jsonWebServiceActionConfig.getMethodParameters();
577
578 int methodParametersCount =
579 jsonWebServiceActionConfigMethodParameters.length;
580
581 if ((hint != -1) && (methodParametersCount != hint)) {
582 continue;
583 }
584
585 int count = _countMatchedParameters(
586 parameterNames, jsonWebServiceActionConfigMethodParameters);
587
588 if (count > max) {
589 if ((hint != -1) || (count >= methodParametersCount)) {
590 max = count;
591
592 index = i;
593 }
594 }
595 }
596
597 if (_log.isDebugEnabled()) {
598 if (index == -1) {
599 _log.debug(
600 "Unable to match parameters to a JSON web service " +
601 "action with path " + path + " for " + contextName);
602 }
603 else {
604 _log.debug(
605 "Matched parameters to a JSON web service action with " +
606 "path " + path + " for " + contextName);
607 }
608 }
609
610 return index;
611 }
612
613 private int _getParameterPathIndex(String path) {
614 int index = path.indexOf(CharPool.SLASH, 1);
615
616 if (index != -1) {
617 index = path.indexOf(CharPool.SLASH, index + 1);
618 }
619
620 return index;
621 }
622
623 private String[] _resolvePaths(HttpServletRequest request, String path) {
624 String contextName = null;
625
626 int index = path.indexOf(CharPool.FORWARD_SLASH, 1);
627
628 if (index != -1) {
629 index = path.lastIndexOf(CharPool.PERIOD, index);
630
631 if (index != -1) {
632 contextName = path.substring(1, index);
633 }
634 }
635
636 if (contextName == null) {
637 ServletContext servletContext = request.getServletContext();
638
639 contextName = servletContext.getServletContextName();
640
641 if (Validator.isNotNull(contextName)) {
642 path = StringPool.SLASH.concat(contextName).concat(
643 StringPool.PERIOD).concat(path.substring(1));
644 }
645 }
646
647 return new String[] {contextName, path};
648 }
649
650 private static Log _log = LogFactoryUtil.getLog(
651 JSONWebServiceActionsManagerImpl.class);
652
653 private SortedArrayList<JSONWebServiceActionConfig>
654 _jsonWebServiceActionConfigs =
655 new SortedArrayList<JSONWebServiceActionConfig>();
656 private JSONWebServiceNaming _jsonWebServiceNaming =
657 new JSONWebServiceNaming();
658 private BinarySearch<String> _pathBinarySearch = new PathBinarySearch();
659
660 private class PathBinarySearch extends BinarySearch<String> {
661
662 @Override
663 protected int compare(int index, String element) {
664 JSONWebServiceActionConfig jsonWebServiceActionConfig =
665 _jsonWebServiceActionConfigs.get(index);
666
667 String path = jsonWebServiceActionConfig.getPath();
668
669 return path.compareTo(element);
670 }
671
672 @Override
673 protected int getLastIndex() {
674 return _jsonWebServiceActionConfigs.size() - 1;
675 }
676
677 }
678
679 }