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