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