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 for (JSONWebServiceActionConfig jsonWebServiceActionConfig :
195 _jsonWebServiceActionConfigs) {
196
197 if (contextName.equals(
198 jsonWebServiceActionConfig.getContextName())) {
199
200 count++;
201 }
202 }
203
204 return count;
205 }
206
207 @Override
208 public JSONWebServiceNaming getJSONWebServiceNaming() {
209 return _jsonWebServiceNaming;
210 }
211
212 @Override
213 public void registerJSONWebServiceAction(
214 String contextName, String contextPath, Class<?> actionClass,
215 Method actionMethod, String path, String method) {
216
217 try {
218 JSONWebServiceActionConfig jsonWebServiceActionConfig =
219 new JSONWebServiceActionConfig(
220 contextName, contextPath, actionClass, actionMethod, path,
221 method);
222
223 if (_jsonWebServiceActionConfigs.contains(
224 jsonWebServiceActionConfig)) {
225
226 if (_log.isDebugEnabled()) {
227 _log.debug(
228 "A JSON web service action is already registered at " +
229 path);
230 }
231
232 return;
233 }
234
235 _jsonWebServiceActionConfigs.add(jsonWebServiceActionConfig);
236 }
237 catch (Exception e) {
238 if (_log.isWarnEnabled()) {
239 StringBundler sb = new StringBundler(14);
240
241 sb.append("Unable to register service method {actionClass=");
242 sb.append(actionClass);
243 sb.append(", actionMethod=");
244 sb.append(actionMethod);
245 sb.append(", contextName=");
246 sb.append(contextName);
247 sb.append(", contextPath=");
248 sb.append(contextPath);
249 sb.append(", method=");
250 sb.append(method);
251 sb.append(", path=");
252 sb.append(path);
253 sb.append("} due to ");
254 sb.append(e.getMessage());
255
256 _log.warn(sb.toString());
257 }
258 }
259 }
260
261 @Override
262 public void registerJSONWebServiceAction(
263 String contextName, String contextPath, Object actionObject,
264 Class<?> actionClass, Method actionMethod, String path, String method) {
265
266 try {
267 JSONWebServiceActionConfig jsonWebServiceActionConfig =
268 new JSONWebServiceActionConfig(
269 contextName, contextPath, actionObject, actionClass,
270 actionMethod, path, method);
271
272 if (_jsonWebServiceActionConfigs.contains(
273 jsonWebServiceActionConfig)) {
274
275 if (_log.isWarnEnabled()) {
276 _log.warn(
277 "A JSON web service action is already registered at " +
278 path);
279 }
280
281 return;
282 }
283
284 _jsonWebServiceActionConfigs.add(jsonWebServiceActionConfig);
285 }
286 catch (Exception e) {
287 StringBundler sb = new StringBundler(17);
288
289 sb.append("Something went wrong attempting to register service ");
290 sb.append("method {contextName=");
291 sb.append(contextName);
292 sb.append(",contextPath=");
293 sb.append(contextPath);
294 sb.append(",actionObject=");
295 sb.append(actionObject);
296 sb.append(",actionClass=");
297 sb.append(actionClass);
298 sb.append(",actionMethod=");
299 sb.append(actionMethod);
300 sb.append(",path=");
301 sb.append(path);
302 sb.append(",method=");
303 sb.append(method);
304 sb.append("} due to ");
305 sb.append(e.getMessage());
306
307 _log.warn(sb.toString());
308 }
309 }
310
311 @Override
312 public int registerService(String contextPath, Object service) {
313 return registerService(StringPool.BLANK, contextPath, service);
314 }
315
316 @Override
317 public int registerService(
318 String contextName, String contextPath, Object service) {
319
320 JSONWebServiceRegistrator jsonWebServiceRegistrator =
321 new JSONWebServiceRegistrator();
322
323 jsonWebServiceRegistrator.processBean(
324 contextName, contextPath, service);
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 registerServletContext(ServletContext servletContext) {
337 BeanLocator beanLocator = null;
338
339 String contextName = servletContext.getServletContextName();
340 String contextPath = servletContext.getContextPath();
341
342 if (contextPath.equals(
343 PortalContextLoaderListener.getPortalServletContextPath()) ||
344 contextPath.isEmpty()) {
345
346 beanLocator = PortalBeanLocatorUtil.getBeanLocator();
347 }
348 else {
349 beanLocator = PortletBeanLocatorUtil.getBeanLocator(contextName);
350 }
351
352 if (beanLocator == null) {
353 if (_log.isInfoEnabled()) {
354 _log.info("Bean locator not available for " + contextPath);
355 }
356
357 return -1;
358 }
359
360 JSONWebServiceRegistrator jsonWebServiceRegistrator =
361 new JSONWebServiceRegistrator();
362
363 jsonWebServiceRegistrator.processAllBeans(
364 contextName, contextPath, beanLocator);
365
366 int count = getJSONWebServiceActionsCount(contextPath);
367
368 if (_log.isInfoEnabled()) {
369 _log.info("Configured " + count + " actions for " + contextPath);
370 }
371
372 return count;
373 }
374
375 @Override
376 public int unregisterJSONWebServiceActions(Object actionObject) {
377 int count = 0;
378
379 Iterator<JSONWebServiceActionConfig> iterator =
380 _jsonWebServiceActionConfigs.iterator();
381
382 while (iterator.hasNext()) {
383 JSONWebServiceActionConfig jsonWebServiceActionConfig =
384 iterator.next();
385
386 if (actionObject.equals(
387 jsonWebServiceActionConfig.getActionObject())) {
388
389 iterator.remove();
390
391 count++;
392 }
393 }
394
395 return count;
396 }
397
398 @Override
399 public int unregisterJSONWebServiceActions(String contextPath) {
400 int count = 0;
401
402 Iterator<JSONWebServiceActionConfig> iterator =
403 _jsonWebServiceActionConfigs.iterator();
404
405 while (iterator.hasNext()) {
406 JSONWebServiceActionConfig jsonWebServiceActionConfig =
407 iterator.next();
408
409 if (contextPath.equals(
410 jsonWebServiceActionConfig.getContextPath())) {
411
412 iterator.remove();
413
414 count++;
415 }
416 }
417
418 return count;
419 }
420
421 @Override
422 public int unregisterServletContext(ServletContext servletContext) {
423 String contextPath = ContextPathUtil.getContextPath(servletContext);
424
425 return unregisterJSONWebServiceActions(contextPath);
426 }
427
428 private int _countMatchedParameters(
429 String[] parameterNames, MethodParameter[] methodParameters) {
430
431 int matched = 0;
432
433 for (MethodParameter methodParameter : methodParameters) {
434 String methodParameterName = methodParameter.getName();
435
436 methodParameterName = StringUtil.toLowerCase(methodParameterName);
437
438 for (String parameterName : parameterNames) {
439 if (StringUtil.equalsIgnoreCase(
440 parameterName, methodParameterName)) {
441
442 matched++;
443 }
444 }
445 }
446
447 return matched;
448 }
449
450 private JSONWebServiceActionConfig _findJSONWebServiceAction(
451 HttpServletRequest request, String path, String method,
452 JSONWebServiceActionParameters jsonWebServiceActionParameters)
453 throws NoSuchJSONWebServiceException {
454
455 String[] paths = _resolvePaths(request, path);
456
457 String contextName = paths[0];
458
459 path = paths[1];
460
461 if (_log.isDebugEnabled()) {
462 _log.debug(
463 "Request JSON web service action with path " + path +
464 " and method " + method + " for " + contextName);
465 }
466
467 String[] parameterNames =
468 jsonWebServiceActionParameters.getParameterNames();
469
470 int jsonWebServiceActionConfigIndex =
471 _getJSONWebServiceActionConfigIndex(
472 contextName, path, method, parameterNames);
473
474 if (jsonWebServiceActionConfigIndex == -1) {
475 if (jsonWebServiceActionParameters.includeDefaultParameters()) {
476 parameterNames =
477 jsonWebServiceActionParameters.getParameterNames();
478
479 jsonWebServiceActionConfigIndex =
480 _getJSONWebServiceActionConfigIndex(
481 contextName, path, method, parameterNames);
482 }
483 }
484
485 if (jsonWebServiceActionConfigIndex == -1) {
486 throw new NoSuchJSONWebServiceException(
487 "No JSON web service action with path " + path +
488 " and method " + method + " for " + contextName);
489 }
490
491 JSONWebServiceActionConfig jsonWebServiceActionConfig =
492 _jsonWebServiceActionConfigs.get(jsonWebServiceActionConfigIndex);
493
494 return jsonWebServiceActionConfig;
495 }
496
497 private int _getJSONWebServiceActionConfigIndex(
498 String contextName, String path, String method,
499 String[] parameterNames) {
500
501 int hint = -1;
502
503 int offset = 0;
504
505 if (Validator.isNotNull(contextName)) {
506 String pathPrefix = StringPool.SLASH.concat(contextName).concat(
507 StringPool.PERIOD);
508
509 if (path.startsWith(pathPrefix)) {
510 offset = pathPrefix.length();
511 }
512 }
513
514 int dotIndex = path.indexOf(CharPool.PERIOD, offset);
515
516 if (dotIndex != -1) {
517 hint = GetterUtil.getInteger(path.substring(dotIndex + 1), -1);
518
519 if (hint != -1) {
520 path = path.substring(0, dotIndex);
521 }
522 }
523
524 int firstIndex = _pathBinarySearch.findFirst(path);
525
526 if (firstIndex < 0) {
527 if (_log.isDebugEnabled()) {
528 _log.debug(
529 "Unable to find JSON web service actions with path " +
530 path + " for " + contextName);
531 }
532
533 return -1;
534 }
535
536 int lastIndex = _pathBinarySearch.findLast(path, firstIndex);
537
538 if (lastIndex < 0) {
539 lastIndex = firstIndex;
540 }
541
542 int index = -1;
543
544 int max = -1;
545
546 if (_log.isDebugEnabled()) {
547 int total = lastIndex - firstIndex + 1;
548
549 _log.debug(
550 "Found " + total + " JSON web service actions with path " +
551 path + " in for " + contextName);
552 }
553
554 for (int i = firstIndex; i <= lastIndex; i++) {
555 JSONWebServiceActionConfig jsonWebServiceActionConfig =
556 _jsonWebServiceActionConfigs.get(i);
557
558 String jsonWebServiceActionConfigMethod =
559 jsonWebServiceActionConfig.getMethod();
560
561 if (PropsValues.JSONWS_WEB_SERVICE_STRICT_HTTP_METHOD &&
562 (method != null)) {
563
564 if ((jsonWebServiceActionConfigMethod != null) &&
565 !jsonWebServiceActionConfigMethod.equals(method)) {
566
567 continue;
568 }
569 }
570
571 MethodParameter[] jsonWebServiceActionConfigMethodParameters =
572 jsonWebServiceActionConfig.getMethodParameters();
573
574 int methodParametersCount =
575 jsonWebServiceActionConfigMethodParameters.length;
576
577 if ((hint != -1) && (methodParametersCount != hint)) {
578 continue;
579 }
580
581 int count = _countMatchedParameters(
582 parameterNames, jsonWebServiceActionConfigMethodParameters);
583
584 if (count > max) {
585 if ((hint != -1) || (count >= methodParametersCount)) {
586 max = count;
587
588 index = i;
589 }
590 }
591 }
592
593 if (_log.isDebugEnabled()) {
594 if (index == -1) {
595 _log.debug(
596 "Unable to match parameters to a JSON web service " +
597 "action with path " + path + " for " + contextName);
598 }
599 else {
600 _log.debug(
601 "Matched parameters to a JSON web service action with " +
602 "path " + path + " for " + contextName);
603 }
604 }
605
606 return index;
607 }
608
609 private int _getParameterPathIndex(String path) {
610 int index = path.indexOf(CharPool.SLASH, 1);
611
612 if (index != -1) {
613 index = path.indexOf(CharPool.SLASH, index + 1);
614 }
615
616 return index;
617 }
618
619 private String[] _resolvePaths(HttpServletRequest request, String path) {
620 String contextName = null;
621
622 int index = path.indexOf(CharPool.FORWARD_SLASH, 1);
623
624 if (index != -1) {
625 index = path.lastIndexOf(CharPool.PERIOD, index);
626
627 if (index != -1) {
628 contextName = path.substring(1, index);
629 }
630 }
631
632 if (contextName == null) {
633 ServletContext servletContext = request.getServletContext();
634
635 contextName = servletContext.getServletContextName();
636
637 if (Validator.isNotNull(contextName)) {
638 path = StringPool.SLASH.concat(contextName).concat(
639 StringPool.PERIOD).concat(path.substring(1));
640 }
641 }
642
643 return new String[] {contextName, path};
644 }
645
646 private static Log _log = LogFactoryUtil.getLog(
647 JSONWebServiceActionsManagerImpl.class);
648
649 private SortedArrayList<JSONWebServiceActionConfig>
650 _jsonWebServiceActionConfigs =
651 new SortedArrayList<JSONWebServiceActionConfig>();
652 private JSONWebServiceNaming _jsonWebServiceNaming =
653 new JSONWebServiceNaming();
654 private BinarySearch<String> _pathBinarySearch = new PathBinarySearch();
655
656 private class PathBinarySearch extends BinarySearch<String> {
657
658 @Override
659 protected int compare(int index, String element) {
660 JSONWebServiceActionConfig jsonWebServiceActionConfig =
661 _jsonWebServiceActionConfigs.get(index);
662
663 String path = jsonWebServiceActionConfig.getPath();
664
665 return path.compareTo(element);
666 }
667
668 @Override
669 protected int getLastIndex() {
670 return _jsonWebServiceActionConfigs.size() - 1;
671 }
672
673 }
674
675 }