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.PortletServlet;
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 void initFilter(
177                            ServletContext servletContext, String filterName,
178                            String filterClassName, Map<String, String> initParameterMap)
179                    throws Exception {
180    
181                    ClassLoader contextClassLoader =
182                            (ClassLoader)servletContext.getAttribute(
183                                    PortletServlet.PORTLET_CLASS_LOADER);
184    
185                    if (contextClassLoader == null) {
186                            Thread currentThread = Thread.currentThread();
187    
188                            contextClassLoader = currentThread.getContextClassLoader();
189                    }
190    
191                    FilterConfig filterConfig = new InvokerFilterConfig(
192                            servletContext, filterName, initParameterMap);
193    
194                    Filter filter = null;
195    
196                    try {
197                            filter = (Filter)InstanceFactory.newInstance(
198                                    contextClassLoader, filterClassName);
199    
200                            filter.init(filterConfig);
201                    }
202                    catch (Exception e) {
203                            _log.error("Unable to initialize filter " + filterClassName, e);
204    
205                            return;
206                    }
207    
208                    boolean filterEnabled = true;
209    
210                    if (filter instanceof LiferayFilter) {
211    
212                            // We no longer remove disabled filters because they can be enabled
213                            // at runtime by a hook. The performance difference is negligible
214                            // since most filters are assumed to be enabled.
215    
216                            //LiferayFilter liferayFilter = (LiferayFilter)filter;
217    
218                            //filterEnabled = liferayFilter.isFilterEnabled();
219                    }
220    
221                    if (filterEnabled) {
222                            _filterConfigs.put(filterName, filterConfig);
223                            _filters.put(filterName, filter);
224                    }
225                    else {
226                            if (filter instanceof PortalLifecycle) {
227                                    PortalLifecycle portalLifecycle = (PortalLifecycle)filter;
228    
229                                    PortalLifecycleUtil.removeDestroy(portalLifecycle);
230                            }
231    
232                            if (_log.isDebugEnabled()) {
233                                    _log.debug("Removing disabled filter " + filter.getClass());
234                            }
235                    }
236            }
237    
238            protected void initFilterMapping(
239                    String filterName, List<String> urlPatterns, List<String> dispatchers) {
240    
241                    Filter filter = _filters.get(filterName);
242    
243                    if (filter == null) {
244                            return;
245                    }
246    
247                    FilterConfig filterConfig = _filterConfigs.get(filterName);
248    
249                    if (filterConfig == null) {
250                            return;
251                    }
252    
253                    FilterMapping filterMapping = new FilterMapping(
254                            filter, filterConfig, urlPatterns, dispatchers);
255    
256                    _filterMappings.add(filterMapping);
257            }
258    
259            protected void readLiferayFilterWebXML(
260                            ServletContext servletContext, String path)
261                    throws Exception {
262    
263                    InputStream inputStream = servletContext.getResourceAsStream(path);
264    
265                    if (inputStream == null) {
266                            return;
267                    }
268    
269                    Document document = SAXReaderUtil.read(inputStream, true);
270    
271                    Element rootElement = document.getRootElement();
272    
273                    List<Element> filterElements = rootElement.elements("filter");
274    
275                    for (Element filterElement : filterElements) {
276                            String filterName = filterElement.elementText("filter-name");
277                            String filterClassName = filterElement.elementText("filter-class");
278    
279                            Map<String, String> initParameterMap =
280                                    new HashMap<String, String>();
281    
282                            List<Element> initParamElements = filterElement.elements(
283                                    "init-param");
284    
285                            for (Element initParamElement : initParamElements) {
286                                    String name = initParamElement.elementText("param-name");
287                                    String value = initParamElement.elementText("param-value");
288    
289                                    initParameterMap.put(name, value);
290                            }
291    
292                            initFilter(
293                                    servletContext, filterName, filterClassName, initParameterMap);
294                    }
295    
296                    List<Element> filterMappingElements = rootElement.elements(
297                            "filter-mapping");
298    
299                    for (Element filterMappingElement : filterMappingElements) {
300                            String filterName = filterMappingElement.elementText("filter-name");
301    
302                            List<String> urlPatterns = new ArrayList<String>();
303    
304                            List<Element> urlPatternElements = filterMappingElement.elements(
305                                    "url-pattern");
306    
307                            for (Element urlPatternElement : urlPatternElements) {
308                                    urlPatterns.add(urlPatternElement.getTextTrim());
309                            }
310    
311                            List<String> dispatchers = new ArrayList<String>(4);
312    
313                            List<Element> dispatcherElements = filterMappingElement.elements(
314                                    "dispatcher");
315    
316                            for (Element dispatcherElement : dispatcherElements) {
317                                    String dispatcher =
318                                            dispatcherElement.getTextTrim().toUpperCase();
319    
320                                    dispatchers.add(dispatcher);
321                            }
322    
323                            initFilterMapping(filterName, urlPatterns, dispatchers);
324                    }
325            }
326    
327            private static Log _log = LogFactoryUtil.getLog(InvokerFilter.class);
328    
329            private Map<String, FilterConfig> _filterConfigs =
330                    new HashMap<String, FilterConfig>();
331            private List<FilterMapping> _filterMappings =
332                    new CopyOnWriteArrayList<FilterMapping>();
333            private Map<String, Filter> _filters = new HashMap<String, Filter>();
334            private List<InvokerFilter> _invokerFilters =
335                    new ArrayList<InvokerFilter>();
336    
337    }