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