001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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.LiferayFilter;
020    import com.liferay.portal.kernel.servlet.PluginContextListener;
021    import com.liferay.portal.kernel.util.InstanceFactory;
022    import com.liferay.portal.kernel.util.PortalLifecycle;
023    import com.liferay.portal.kernel.util.PortalLifecycleUtil;
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    
030    import java.io.InputStream;
031    
032    import java.util.ArrayList;
033    import java.util.HashMap;
034    import java.util.List;
035    import java.util.Map;
036    import java.util.concurrent.CopyOnWriteArrayList;
037    
038    import javax.servlet.Filter;
039    import javax.servlet.FilterChain;
040    import javax.servlet.FilterConfig;
041    import javax.servlet.ServletContext;
042    import javax.servlet.ServletException;
043    import javax.servlet.http.HttpServletRequest;
044    
045    /**
046     * @author Mika Koivisto
047     * @author Brian Wing Shun Chan
048     */
049    public class InvokerFilterHelper {
050    
051            public void destroy() {
052                    for (Map.Entry<String, Filter> entry : _filters.entrySet()) {
053                            Filter filter = entry.getValue();
054    
055                            if (filter == null) {
056                                    continue;
057                            }
058    
059                            try {
060                                    filter.destroy();
061                            }
062                            catch (Exception e) {
063                                    _log.error(e, e);
064                            }
065                    }
066    
067                    _filterConfigs.clear();
068                    _filterMappings.clear();
069                    _filters.clear();
070    
071                    for (InvokerFilter invokerFilter : _invokerFilters) {
072                            invokerFilter.clearFilterChainsCache();
073                    }
074            }
075    
076            public Filter getFilter(String filterName) {
077                    return _filters.get(filterName);
078            }
079    
080            public FilterConfig getFilterConfig(String filterName) {
081                    return _filterConfigs.get(filterName);
082            }
083    
084            public void init(FilterConfig filterConfig) throws ServletException {
085                    try {
086                            ServletContext servletContext = filterConfig.getServletContext();
087    
088                            readLiferayFilterWebXML(servletContext, "/WEB-INF/liferay-web.xml");
089                    }
090                    catch (Exception e) {
091                            _log.error(e, e);
092    
093                            throw new ServletException(e);
094                    }
095            }
096    
097            public Filter registerFilter(String filterName, Filter filter) {
098                    Filter previousFilter = _filters.put(filterName, filter);
099    
100                    if (previousFilter != null) {
101                            for (FilterMapping filterMapping : _filterMappings) {
102                                    if (filterMapping.getFilter() == previousFilter) {
103                                            if (filter != null) {
104                                                    filterMapping.setFilter(filter);
105                                            }
106                                            else {
107                                                    _filterMappings.remove(filterMapping);
108                                                    _filterConfigs.remove(filterName);
109                                            }
110                                    }
111                            }
112                    }
113    
114                    for (InvokerFilter invokerFilter : _invokerFilters) {
115                            invokerFilter.clearFilterChainsCache();
116                    }
117    
118                    return previousFilter;
119            }
120    
121            public void registerFilterMapping(
122                    FilterMapping filterMapping, String filterName, boolean after) {
123    
124                    int i = 0;
125    
126                    if (Validator.isNotNull(filterName)) {
127                            Filter filter = _filters.get(filterName);
128    
129                            if (filter != null) {
130                                    for (; i < _filterMappings.size(); i++) {
131                                            FilterMapping currentFilterMapping = _filterMappings.get(i);
132    
133                                            if (currentFilterMapping.getFilter() == filter) {
134                                                    break;
135                                            }
136                                    }
137                            }
138                    }
139    
140                    if (after) {
141                            i++;
142                    }
143    
144                    _filterMappings.add(i, filterMapping);
145    
146                    for (InvokerFilter invokerFilter : _invokerFilters) {
147                            invokerFilter.clearFilterChainsCache();
148                    }
149            }
150    
151            public void unregisterFilter(String filterName) {
152                    Filter filter = _filters.remove(filterName);
153    
154                    if (filter == null) {
155                            return;
156                    }
157    
158                    for (FilterMapping filterMapping : _filterMappings) {
159                            if (filterMapping.getFilter() == filter) {
160                                    unregisterFilterMapping(filterMapping);
161    
162                                    break;
163                            }
164                    }
165    
166                    _filterConfigs.remove(filterName);
167    
168                    try {
169                            filter.destroy();
170                    }
171                    catch (Exception e) {
172                            _log.error(e, e);
173                    }
174            }
175    
176            public void unregisterFilterMapping(FilterMapping filterMapping) {
177                    _filterMappings.remove(filterMapping);
178    
179                    for (InvokerFilter invokerFilter : _invokerFilters) {
180                            invokerFilter.clearFilterChainsCache();
181                    }
182            }
183    
184            protected void addInvokerFilter(InvokerFilter invokerFilter) {
185                    _invokerFilters.add(invokerFilter);
186            }
187    
188            protected InvokerFilterChain createInvokerFilterChain(
189                    HttpServletRequest request, Dispatcher dispatcher, String uri,
190                    FilterChain filterChain) {
191    
192                    InvokerFilterChain invokerFilterChain = new InvokerFilterChain(
193                            filterChain);
194    
195                    for (FilterMapping filterMapping : _filterMappings) {
196                            if (filterMapping.isMatch(request, dispatcher, uri)) {
197                                    Filter filter = filterMapping.getFilter();
198    
199                                    invokerFilterChain.addFilter(filter);
200                            }
201                    }
202    
203                    return invokerFilterChain;
204            }
205    
206            protected Filter getFilter(
207                    ServletContext servletContext, String filterClassName,
208                    FilterConfig filterConfig) {
209    
210                    ClassLoader pluginClassLoader = getPluginClassLoader(servletContext);
211    
212                    Thread currentThread = Thread.currentThread();
213    
214                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
215    
216                    try {
217                            if (contextClassLoader != pluginClassLoader) {
218                                    currentThread.setContextClassLoader(pluginClassLoader);
219                            }
220    
221                            Filter filter = (Filter)InstanceFactory.newInstance(
222                                    pluginClassLoader, filterClassName);
223    
224                            filter.init(filterConfig);
225    
226                            return filter;
227                    }
228                    catch (Exception e) {
229                            _log.error("Unable to initialize filter " + filterClassName, e);
230                    }
231                    finally {
232                            if (contextClassLoader != pluginClassLoader) {
233                                    currentThread.setContextClassLoader(contextClassLoader);
234                            }
235                    }
236    
237                    return null;
238            }
239    
240            protected ClassLoader getPluginClassLoader(ServletContext servletContext) {
241                    ClassLoader classLoader = (ClassLoader)servletContext.getAttribute(
242                            PluginContextListener.PLUGIN_CLASS_LOADER);
243    
244                    if (classLoader != null) {
245                            return classLoader;
246                    }
247    
248                    Thread currentThread = Thread.currentThread();
249    
250                    return currentThread.getContextClassLoader();
251            }
252    
253            protected void initFilter(
254                            ServletContext servletContext, String filterName,
255                            String filterClassName, Map<String, String> initParameterMap)
256                    throws Exception {
257    
258                    FilterConfig filterConfig = new InvokerFilterConfig(
259                            servletContext, filterName, initParameterMap);
260    
261                    Filter filter = getFilter(
262                            servletContext, filterClassName, filterConfig);
263    
264                    if (filter == null) {
265                            return;
266                    }
267    
268                    boolean filterEnabled = true;
269    
270                    if (filter instanceof LiferayFilter) {
271    
272                            // We no longer remove disabled filters because they can be enabled
273                            // at runtime by a hook. The performance difference is negligible
274                            // since most filters are assumed to be enabled.
275    
276                            //LiferayFilter liferayFilter = (LiferayFilter)filter;
277    
278                            //filterEnabled = liferayFilter.isFilterEnabled();
279                    }
280    
281                    if (filterEnabled) {
282                            _filterConfigs.put(filterName, filterConfig);
283                            _filters.put(filterName, filter);
284                    }
285                    else {
286                            if (filter instanceof PortalLifecycle) {
287                                    PortalLifecycle portalLifecycle = (PortalLifecycle)filter;
288    
289                                    PortalLifecycleUtil.removeDestroy(portalLifecycle);
290                            }
291    
292                            if (_log.isDebugEnabled()) {
293                                    _log.debug("Removing disabled filter " + filter.getClass());
294                            }
295                    }
296            }
297    
298            protected void initFilterMapping(
299                    String filterName, List<String> urlPatterns, List<String> dispatchers) {
300    
301                    Filter filter = _filters.get(filterName);
302    
303                    if (filter == null) {
304                            return;
305                    }
306    
307                    FilterConfig filterConfig = _filterConfigs.get(filterName);
308    
309                    if (filterConfig == null) {
310                            return;
311                    }
312    
313                    FilterMapping filterMapping = new FilterMapping(
314                            filter, filterConfig, urlPatterns, dispatchers);
315    
316                    _filterMappings.add(filterMapping);
317            }
318    
319            protected void readLiferayFilterWebXML(
320                            ServletContext servletContext, String path)
321                    throws Exception {
322    
323                    InputStream inputStream = servletContext.getResourceAsStream(path);
324    
325                    if (inputStream == null) {
326                            return;
327                    }
328    
329                    Document document = UnsecureSAXReaderUtil.read(inputStream, true);
330    
331                    Element rootElement = document.getRootElement();
332    
333                    List<Element> filterElements = rootElement.elements("filter");
334    
335                    for (Element filterElement : filterElements) {
336                            String filterName = filterElement.elementText("filter-name");
337                            String filterClassName = filterElement.elementText("filter-class");
338    
339                            Map<String, String> initParameterMap =
340                                    new HashMap<String, String>();
341    
342                            List<Element> initParamElements = filterElement.elements(
343                                    "init-param");
344    
345                            for (Element initParamElement : initParamElements) {
346                                    String name = initParamElement.elementText("param-name");
347                                    String value = initParamElement.elementText("param-value");
348    
349                                    initParameterMap.put(name, value);
350                            }
351    
352                            initFilter(
353                                    servletContext, filterName, filterClassName, initParameterMap);
354                    }
355    
356                    List<Element> filterMappingElements = rootElement.elements(
357                            "filter-mapping");
358    
359                    for (Element filterMappingElement : filterMappingElements) {
360                            String filterName = filterMappingElement.elementText("filter-name");
361    
362                            List<String> urlPatterns = new ArrayList<String>();
363    
364                            List<Element> urlPatternElements = filterMappingElement.elements(
365                                    "url-pattern");
366    
367                            for (Element urlPatternElement : urlPatternElements) {
368                                    urlPatterns.add(urlPatternElement.getTextTrim());
369                            }
370    
371                            List<String> dispatchers = new ArrayList<String>(4);
372    
373                            List<Element> dispatcherElements = filterMappingElement.elements(
374                                    "dispatcher");
375    
376                            for (Element dispatcherElement : dispatcherElements) {
377                                    String dispatcher = StringUtil.toUpperCase(
378                                            dispatcherElement.getTextTrim());
379    
380                                    dispatchers.add(dispatcher);
381                            }
382    
383                            initFilterMapping(filterName, urlPatterns, dispatchers);
384                    }
385            }
386    
387            private static Log _log = LogFactoryUtil.getLog(InvokerFilterHelper.class);
388    
389            private Map<String, FilterConfig> _filterConfigs =
390                    new HashMap<String, FilterConfig>();
391            private List<FilterMapping> _filterMappings =
392                    new CopyOnWriteArrayList<FilterMapping>();
393            private Map<String, Filter> _filters = new HashMap<String, Filter>();
394            private List<InvokerFilter> _invokerFilters =
395                    new ArrayList<InvokerFilter>();
396    
397    }