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