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