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