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 = servletContext.getServletContextName();
295
296 int count = registerServletContext(contextPath);
297
298 return count;
299 }
300
301 @Override
302 public int registerServletContext(String contextPath) {
303 BeanLocator beanLocator = null;
304
305 if (contextPath.equals(
306 PortalContextLoaderListener.getPortalServletContextPath()) ||
307 contextPath.isEmpty()) {
308
309 beanLocator = PortalBeanLocatorUtil.getBeanLocator();
310 }
311 else {
312 String contextName = contextPath;
313
314 if (!contextPath.startsWith(StringPool.SLASH)) {
315 contextPath = StringPool.SLASH.concat(contextPath);
316 }
317
318 beanLocator = PortletBeanLocatorUtil.getBeanLocator(contextName);
319 }
320
321 if (beanLocator == null) {
322 if (_log.isInfoEnabled()) {
323 _log.info("Bean locator not available for " + contextPath);
324 }
325
326 return -1;
327 }
328
329 JSONWebServiceRegistrator jsonWebServiceRegistrator =
330 new JSONWebServiceRegistrator();
331
332 jsonWebServiceRegistrator.processAllBeans(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 int unregisterJSONWebServiceActions(Object actionObject) {
345 int count = 0;
346
347 Iterator<JSONWebServiceActionConfig> iterator =
348 _jsonWebServiceActionConfigs.iterator();
349
350 while (iterator.hasNext()) {
351 JSONWebServiceActionConfig jsonWebServiceActionConfig =
352 iterator.next();
353
354 if (actionObject.equals(
355 jsonWebServiceActionConfig.getActionObject())) {
356
357 iterator.remove();
358
359 count++;
360 }
361 }
362
363 return count;
364 }
365
366 @Override
367 public int unregisterJSONWebServiceActions(String contextPath) {
368 int count = 0;
369
370 Iterator<JSONWebServiceActionConfig> iterator =
371 _jsonWebServiceActionConfigs.iterator();
372
373 while (iterator.hasNext()) {
374 JSONWebServiceActionConfig jsonWebServiceActionConfig =
375 iterator.next();
376
377 if (contextPath.equals(
378 jsonWebServiceActionConfig.getContextPath())) {
379
380 iterator.remove();
381
382 count++;
383 }
384 }
385
386 return count;
387 }
388
389 @Override
390 public int unregisterServletContext(ServletContext servletContext) {
391 String contextPath = ContextPathUtil.getContextPath(servletContext);
392
393 return unregisterJSONWebServiceActions(contextPath);
394 }
395
396 private int _countMatchedElements(
397 String[] parameterNames, MethodParameter[] methodParameters) {
398
399 int matched = 0;
400
401 for (MethodParameter methodParameter : methodParameters) {
402 String methodParameterName = methodParameter.getName();
403
404 methodParameterName = CamelCaseUtil.normalizeCamelCase(
405 methodParameterName);
406
407 if (ArrayUtil.contains(parameterNames, methodParameterName)) {
408 matched++;
409 }
410 }
411
412 return matched;
413 }
414
415 private int _getJSONWebServiceActionConfigIndex(
416 String contextPath, String path, String method,
417 String[] parameterNames) {
418
419 int hint = -1;
420
421 int dotIndex = path.indexOf(CharPool.PERIOD);
422
423 if (dotIndex != -1) {
424 hint = GetterUtil.getInteger(path.substring(dotIndex + 1));
425
426 path = path.substring(0, dotIndex);
427 }
428
429 path = contextPath + path;
430
431 int firstIndex = _pathBinarySearch.findFirst(path);
432
433 if (firstIndex < 0) {
434 if (_log.isDebugEnabled()) {
435 _log.debug(
436 "Unable to find JSON web service actions with path " +
437 path + " for /" + contextPath);
438 }
439
440 return -1;
441 }
442
443 int lastIndex = _pathBinarySearch.findLast(path, firstIndex);
444
445 if (lastIndex < 0) {
446 lastIndex = firstIndex;
447 }
448
449 int index = -1;
450
451 int max = -1;
452
453 if (_log.isDebugEnabled()) {
454 int total = lastIndex - firstIndex + 1;
455
456 _log.debug(
457 "Found " + total + " JSON web service actions with path " +
458 path + " in for /" + contextPath);
459 }
460
461 for (int i = firstIndex; i <= lastIndex; i++) {
462 JSONWebServiceActionConfig jsonWebServiceActionConfig =
463 _jsonWebServiceActionConfigs.get(i);
464
465 String jsonWebServiceActionConfigMethod =
466 jsonWebServiceActionConfig.getMethod();
467
468 if (PropsValues.JSONWS_WEB_SERVICE_STRICT_HTTP_METHOD &&
469 (method != null)) {
470
471 if ((jsonWebServiceActionConfigMethod != null) &&
472 !jsonWebServiceActionConfigMethod.equals(method)) {
473
474 continue;
475 }
476 }
477
478 MethodParameter[] jsonWebServiceActionConfigMethodParameters =
479 jsonWebServiceActionConfig.getMethodParameters();
480
481 int methodParametersCount =
482 jsonWebServiceActionConfigMethodParameters.length;
483
484 if ((hint != -1) && (methodParametersCount != hint)) {
485 continue;
486 }
487
488 int count = _countMatchedElements(
489 parameterNames, jsonWebServiceActionConfigMethodParameters);
490
491 if (count > max) {
492 if ((hint != -1) || (count >= methodParametersCount)) {
493 max = count;
494
495 index = i;
496 }
497 }
498 }
499
500 if (_log.isDebugEnabled()) {
501 if (index == -1) {
502 _log.debug(
503 "Unable to match parameters to a JSON web service " +
504 "action with path " + path + " for /" +
505 contextPath);
506 }
507 else {
508 _log.debug(
509 "Matched parameters to a JSON web service action with " +
510 "path " + path + " for /" + contextPath);
511 }
512 }
513
514 return index;
515 }
516
517 private int _getParameterPathIndex(String path) {
518 int index = path.indexOf(CharPool.SLASH, 1);
519
520 if (index != -1) {
521 index = path.indexOf(CharPool.SLASH, index + 1);
522 }
523
524 return index;
525 }
526
527 private String[] _resolvePaths(HttpServletRequest request, String path) {
528 String contextPath = null;
529
530 int index = path.indexOf(CharPool.FORWARD_SLASH, 1);
531
532 if (index != -1) {
533 index = path.lastIndexOf(CharPool.PERIOD, index);
534
535 if (index != -1) {
536 contextPath = path.substring(0, index);
537
538 path = CharPool.FORWARD_SLASH + path.substring(index + 1);
539 }
540 }
541
542 if (contextPath == null) {
543 HttpSession session = request.getSession();
544
545 ServletContext servletContext = session.getServletContext();
546
547 contextPath = ContextPathUtil.getContextPath(servletContext);
548 }
549
550 return new String[] {contextPath, path};
551 }
552
553 private static Log _log = LogFactoryUtil.getLog(
554 JSONWebServiceActionsManagerImpl.class);
555
556 private SortedArrayList<JSONWebServiceActionConfig>
557 _jsonWebServiceActionConfigs =
558 new SortedArrayList<JSONWebServiceActionConfig>();
559 private BinarySearch<String> _pathBinarySearch = new PathBinarySearch();
560
561 private class PathBinarySearch extends BinarySearch<String> {
562
563 @Override
564 protected int compare(int index, String element) {
565 JSONWebServiceActionConfig jsonWebServiceActionConfig =
566 _jsonWebServiceActionConfigs.get(index);
567
568 String fullPath = jsonWebServiceActionConfig.getFullPath();
569
570 return fullPath.compareTo(element);
571 }
572
573 @Override
574 protected int getLastIndex() {
575 return _jsonWebServiceActionConfigs.size() - 1;
576 }
577
578 }
579
580 }