001
014
015 package com.liferay.portal.kernel.servlet.filters.invoker;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.servlet.PluginContextListener;
020 import com.liferay.portal.kernel.servlet.ServletContextPool;
021 import com.liferay.portal.kernel.util.AggregateClassLoader;
022 import com.liferay.portal.kernel.util.GetterUtil;
023 import com.liferay.portal.kernel.util.InstanceFactory;
024 import com.liferay.portal.kernel.util.ObjectValuePair;
025 import com.liferay.portal.kernel.util.PortalClassLoaderUtil;
026 import com.liferay.portal.kernel.util.StringUtil;
027 import com.liferay.portal.kernel.util.Validator;
028 import com.liferay.portal.kernel.xml.Document;
029 import com.liferay.portal.kernel.xml.Element;
030 import com.liferay.portal.kernel.xml.UnsecureSAXReaderUtil;
031 import com.liferay.registry.Registry;
032 import com.liferay.registry.RegistryUtil;
033 import com.liferay.registry.ServiceReference;
034 import com.liferay.registry.ServiceTracker;
035 import com.liferay.registry.ServiceTrackerCustomizer;
036 import com.liferay.registry.util.StringPlus;
037
038 import java.io.InputStream;
039
040 import java.util.ArrayList;
041 import java.util.HashMap;
042 import java.util.List;
043 import java.util.Map;
044 import java.util.concurrent.ConcurrentHashMap;
045 import java.util.concurrent.ConcurrentMap;
046 import java.util.concurrent.CopyOnWriteArrayList;
047
048 import javax.servlet.Filter;
049 import javax.servlet.FilterChain;
050 import javax.servlet.FilterConfig;
051 import javax.servlet.ServletContext;
052 import javax.servlet.ServletException;
053 import javax.servlet.http.HttpServletRequest;
054
055
059 public class InvokerFilterHelper {
060
061 public void destroy() {
062 _serviceTracker.close();
063
064 for (List<FilterMapping> filterMappings : _filterMappingsMap.values()) {
065 FilterMapping filterMapping = filterMappings.get(0);
066
067 Filter filter = filterMapping.getFilter();
068
069 try {
070 filter.destroy();
071 }
072 catch (Exception e) {
073 _log.error(e, e);
074 }
075 }
076
077 _filterMappingsMap.clear();
078 _filterNames.clear();
079
080 clearFilterChainsCache();
081 }
082
083 public void init(FilterConfig filterConfig) throws ServletException {
084 try {
085 ServletContext servletContext = filterConfig.getServletContext();
086
087 readLiferayFilterWebXML(servletContext, "/WEB-INF/liferay-web.xml");
088
089 Registry registry = RegistryUtil.getRegistry();
090
091 String servletContextName = GetterUtil.getString(
092 servletContext.getServletContextName());
093
094 com.liferay.registry.Filter filter = registry.getFilter(
095 "(&(objectClass=" + Filter.class.getName() +
096 ")(servlet-context-name=" + servletContextName +
097 ")(servlet-filter-name=*))");
098
099 _serviceTracker = registry.trackServices(
100 filter, new FilterServiceTrackerCustomizer());
101
102 _serviceTracker.open();
103 }
104 catch (Exception e) {
105 _log.error(e, e);
106
107 throw new ServletException(e);
108 }
109 }
110
111 public void registerFilterMapping(
112 FilterMapping filterMapping, String positionFilterName, boolean after) {
113
114 String filterName = filterMapping.getFilterName();
115
116 while (true) {
117 List<FilterMapping> oldFilterMappings = _filterMappingsMap.get(
118 filterName);
119
120 List<FilterMapping> newFilterMappings = null;
121
122 if (oldFilterMappings == null) {
123 newFilterMappings = new ArrayList<>();
124 }
125 else {
126 newFilterMappings = new ArrayList<>(oldFilterMappings);
127 }
128
129 newFilterMappings.add(filterMapping);
130
131 if (newFilterMappings.size() == 1) {
132 if (_filterMappingsMap.putIfAbsent(
133 filterName, newFilterMappings) == null) {
134
135 int index = _filterNames.indexOf(positionFilterName);
136
137 if (index == -1) {
138 _filterNames.add(filterName);
139 }
140 else if (after) {
141 _filterNames.add(index + 1, filterName);
142 }
143 else {
144 _filterNames.add(index, filterName);
145 }
146
147 break;
148 }
149 }
150 else if (_filterMappingsMap.replace(
151 filterName, oldFilterMappings, newFilterMappings)) {
152
153 break;
154 }
155 }
156 }
157
158 public void unregisterFilterMapping(FilterMapping filterMapping) {
159 String filterName = filterMapping.getFilterName();
160
161 while (true) {
162 List<FilterMapping> oldFilterMappings = _filterMappingsMap.get(
163 filterName);
164
165 List<FilterMapping> newFilterMappings = new ArrayList<>(
166 oldFilterMappings);
167
168 newFilterMappings.remove(filterMapping);
169
170 if (newFilterMappings.isEmpty()) {
171 if (_filterMappingsMap.remove(filterName, oldFilterMappings)) {
172 _filterNames.remove(filterName);
173
174 break;
175 }
176 }
177 else if (_filterMappingsMap.replace(
178 filterName, oldFilterMappings, newFilterMappings)) {
179
180 break;
181 }
182 }
183 }
184
185 public void unregisterFilterMappings(String filterName) {
186 List<FilterMapping> filterMappings = _filterMappingsMap.remove(
187 filterName);
188
189 if (filterMappings == null) {
190 return;
191 }
192
193 FilterMapping filterMapping = filterMappings.get(0);
194
195 Filter filter = filterMapping.getFilter();
196
197 if (filter != null) {
198 try {
199 filter.destroy();
200 }
201 catch (Exception e) {
202 _log.error(e, e);
203 }
204 }
205
206 _filterNames.remove(filterName);
207
208 clearFilterChainsCache();
209 }
210
211 public void updateFilterMappings(String filterName, Filter filter) {
212 while (true) {
213 List<FilterMapping> oldFilterMappings = _filterMappingsMap.get(
214 filterName);
215
216 if (oldFilterMappings == null) {
217 if (_log.isWarnEnabled()) {
218 _log.warn(
219 "No filter mappings for filter name " + filterName);
220 }
221
222 return;
223 }
224
225 List<FilterMapping> newFilterMappings = new ArrayList<>();
226
227 for (FilterMapping oldFilterMapping : oldFilterMappings) {
228 newFilterMappings.add(oldFilterMapping.replaceFilter(filter));
229 }
230
231 if (_filterMappingsMap.replace(
232 filterName, oldFilterMappings, newFilterMappings)) {
233
234 break;
235 }
236 }
237 }
238
239 protected void addInvokerFilter(InvokerFilter invokerFilter) {
240 _invokerFilters.add(invokerFilter);
241 }
242
243 protected void clearFilterChainsCache() {
244 for (InvokerFilter invokerFilter : _invokerFilters) {
245 invokerFilter.clearFilterChainsCache();
246 }
247 }
248
249 protected InvokerFilterChain createInvokerFilterChain(
250 HttpServletRequest request, Dispatcher dispatcher, String uri,
251 FilterChain filterChain) {
252
253 InvokerFilterChain invokerFilterChain = new InvokerFilterChain(
254 filterChain);
255
256 for (String filterName : _filterNames) {
257 List<FilterMapping> filterMappings = _filterMappingsMap.get(
258 filterName);
259
260 if (filterMappings == null) {
261 continue;
262 }
263
264 for (FilterMapping filterMapping : filterMappings) {
265 if (filterMapping.isMatch(request, dispatcher, uri)) {
266 invokerFilterChain.addFilter(filterMapping.getFilter());
267 }
268 }
269 }
270
271 return invokerFilterChain;
272 }
273
274 protected Filter initFilter(
275 ServletContext servletContext, String filterClassName,
276 FilterConfig filterConfig) {
277
278 ClassLoader pluginClassLoader =
279 (ClassLoader)servletContext.getAttribute(
280 PluginContextListener.PLUGIN_CLASS_LOADER);
281
282 Thread currentThread = Thread.currentThread();
283
284 ClassLoader contextClassLoader = currentThread.getContextClassLoader();
285
286 if (pluginClassLoader == null) {
287 pluginClassLoader = contextClassLoader;
288 }
289
290 ClassLoader portalClassLoader = PortalClassLoaderUtil.getClassLoader();
291
292 if (portalClassLoader != pluginClassLoader) {
293 pluginClassLoader = AggregateClassLoader.getAggregateClassLoader(
294 portalClassLoader, pluginClassLoader);
295 }
296
297 if (contextClassLoader != pluginClassLoader) {
298 currentThread.setContextClassLoader(pluginClassLoader);
299 }
300
301 try {
302 Filter filter = (Filter)InstanceFactory.newInstance(
303 pluginClassLoader, filterClassName);
304
305 filter.init(filterConfig);
306
307 return filter;
308 }
309 catch (Exception e) {
310 _log.error("Unable to initialize filter " + filterClassName, e);
311
312 return null;
313 }
314 finally {
315 if (contextClassLoader != pluginClassLoader) {
316 currentThread.setContextClassLoader(contextClassLoader);
317 }
318 }
319 }
320
321
325 @Deprecated
326 protected Filter initFilter(
327 ServletContext servletContext, String filterClassName,
328 String filterName, FilterConfig filterConfig) {
329
330 return initFilter(servletContext, filterClassName, filterConfig);
331 }
332
333 protected void readLiferayFilterWebXML(
334 ServletContext servletContext, String path)
335 throws Exception {
336
337 InputStream inputStream = servletContext.getResourceAsStream(path);
338
339 if (inputStream == null) {
340 return;
341 }
342
343 Document document = UnsecureSAXReaderUtil.read(inputStream, true);
344
345 Element rootElement = document.getRootElement();
346
347 Map<String, ObjectValuePair<Filter, FilterConfig>>
348 filterObjectValuePairs = new HashMap<>();
349
350 for (Element filterElement : rootElement.elements("filter")) {
351 String filterName = filterElement.elementText("filter-name");
352 String filterClassName = filterElement.elementText("filter-class");
353
354 Map<String, String> initParameterMap = new HashMap<>();
355
356 List<Element> initParamElements = filterElement.elements(
357 "init-param");
358
359 for (Element initParamElement : initParamElements) {
360 String name = initParamElement.elementText("param-name");
361 String value = initParamElement.elementText("param-value");
362
363 initParameterMap.put(name, value);
364 }
365
366 FilterConfig filterConfig = new InvokerFilterConfig(
367 servletContext, filterName, initParameterMap);
368
369 Filter filter = initFilter(
370 servletContext, filterClassName, filterConfig);
371
372 if (filter != null) {
373 filterObjectValuePairs.put(
374 filterName, new ObjectValuePair<>(filter, filterConfig));
375 }
376 }
377
378 List<Element> filterMappingElements = rootElement.elements(
379 "filter-mapping");
380
381 for (Element filterMappingElement : filterMappingElements) {
382 String filterName = filterMappingElement.elementText("filter-name");
383
384 List<String> urlPatterns = new ArrayList<>();
385
386 List<Element> urlPatternElements = filterMappingElement.elements(
387 "url-pattern");
388
389 for (Element urlPatternElement : urlPatternElements) {
390 urlPatterns.add(urlPatternElement.getTextTrim());
391 }
392
393 List<String> dispatchers = new ArrayList<>(4);
394
395 List<Element> dispatcherElements = filterMappingElement.elements(
396 "dispatcher");
397
398 for (Element dispatcherElement : dispatcherElements) {
399 String dispatcher = StringUtil.toUpperCase(
400 dispatcherElement.getTextTrim());
401
402 dispatchers.add(dispatcher);
403 }
404
405 ObjectValuePair<Filter, FilterConfig> filterObjectValuePair =
406 filterObjectValuePairs.get(filterName);
407
408 if (filterObjectValuePair == null) {
409 if (_log.isWarnEnabled()) {
410 _log.warn(
411 "No filter and filter config for filter name " +
412 filterName);
413 }
414
415 continue;
416 }
417
418 FilterMapping filterMapping = new FilterMapping(
419 filterName, filterObjectValuePair.getKey(),
420 filterObjectValuePair.getValue(), urlPatterns, dispatchers);
421
422 registerFilterMapping(filterMapping, null, true);
423 }
424 }
425
426 private static final Log _log = LogFactoryUtil.getLog(
427 InvokerFilterHelper.class);
428
429 private final ConcurrentMap<String, List<FilterMapping>>
430 _filterMappingsMap = new ConcurrentHashMap<>();
431 private final List<String> _filterNames = new CopyOnWriteArrayList<>();
432 private final List<InvokerFilter> _invokerFilters = new ArrayList<>();
433 private ServiceTracker<Filter, FilterMapping> _serviceTracker;
434
435 private class FilterServiceTrackerCustomizer
436 implements ServiceTrackerCustomizer<Filter, FilterMapping> {
437
438 @Override
439 public FilterMapping addingService(
440 ServiceReference<Filter> serviceReference) {
441
442 Registry registry = RegistryUtil.getRegistry();
443
444 Filter filter = registry.getService(serviceReference);
445
446 String afterFilter = GetterUtil.getString(
447 serviceReference.getProperty("after-filter"));
448 String beforeFilter = GetterUtil.getString(
449 serviceReference.getProperty("before-filter"));
450 List<String> dispatchers = StringPlus.asList(
451 serviceReference.getProperty("dispatcher"));
452 String servletContextName = GetterUtil.getString(
453 serviceReference.getProperty("servlet-context-name"));
454 String servletFilterName = GetterUtil.getString(
455 serviceReference.getProperty("servlet-filter-name"));
456 List<String> urlPatterns = StringPlus.asList(
457 serviceReference.getProperty("url-pattern"));
458
459 String positionFilterName = beforeFilter;
460 boolean after = false;
461
462 if (Validator.isNotNull(afterFilter)) {
463 positionFilterName = afterFilter;
464 after = true;
465 }
466
467 Map<String, String> initParameterMap = new HashMap<>();
468
469 Map<String, Object> properties = serviceReference.getProperties();
470
471 for (String key : properties.keySet()) {
472 if (!key.startsWith("init.param.")) {
473 continue;
474 }
475
476 String value = GetterUtil.getString(
477 serviceReference.getProperty(key));
478
479 initParameterMap.put(key, value);
480 }
481
482 ServletContext servletContext = ServletContextPool.get(
483 servletContextName);
484
485 FilterConfig filterConfig = new InvokerFilterConfig(
486 servletContext, servletFilterName, initParameterMap);
487
488 try {
489 filter.init(filterConfig);
490 }
491 catch (ServletException se) {
492 _log.error(se, se);
493
494 registry.ungetService(serviceReference);
495
496 return null;
497 }
498
499 updateFilterMappings(servletFilterName, filter);
500
501 FilterMapping filterMapping = new FilterMapping(
502 servletFilterName, filter, filterConfig, urlPatterns,
503 dispatchers);
504
505 registerFilterMapping(filterMapping, positionFilterName, after);
506
507 clearFilterChainsCache();
508
509 return filterMapping;
510 }
511
512 @Override
513 public void modifiedService(
514 ServiceReference<Filter> serviceReference,
515 FilterMapping filterMapping) {
516
517 removedService(serviceReference, filterMapping);
518
519 addingService(serviceReference);
520 }
521
522 @Override
523 public void removedService(
524 ServiceReference<Filter> serviceReference,
525 FilterMapping filterMapping) {
526
527 Registry registry = RegistryUtil.getRegistry();
528
529 registry.ungetService(serviceReference);
530
531 unregisterFilterMappings(
532 GetterUtil.getString(
533 serviceReference.getProperty("servlet-filter-name")));
534 }
535
536 }
537
538 }