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                    Filter filter = (Filter)InstanceFactory.newInstance(
192                            contextClassLoader, filterClassName);
193    
194                    FilterConfig filterConfig = new InvokerFilterConfig(
195                            servletContext, filterName, initParameterMap);
196    
197                    filter.init(filterConfig);
198    
199                    boolean filterEnabled = true;
200    
201                    if (filter instanceof LiferayFilter) {
202                            LiferayFilter liferayFilter = (LiferayFilter)filter;
203    
204                            filterEnabled = liferayFilter.isFilterEnabled();
205                    }
206    
207                    if (filterEnabled) {
208                            _filterConfigs.put(filterName, filterConfig);
209                            _filters.put(filterName, filter);
210                    }
211                    else {
212                            if (filter instanceof PortalLifecycle) {
213                                    PortalLifecycle portalLifecycle = (PortalLifecycle)filter;
214    
215                                    PortalLifecycleUtil.removeDestroy(portalLifecycle);
216                            }
217    
218                            if (_log.isDebugEnabled()) {
219                                    _log.debug("Removing disabled filter " + filter.getClass());
220                            }
221                    }
222            }
223    
224            protected void initFilterMapping(
225                    String filterName, List<String> urlPatterns, List<String> dispatchers) {
226    
227                    Filter filter = _filters.get(filterName);
228    
229                    if (filter == null) {
230                            return;
231                    }
232    
233                    FilterConfig filterConfig = _filterConfigs.get(filterName);
234    
235                    if (filterConfig == null) {
236                            return;
237                    }
238    
239                    FilterMapping filterMapping = new FilterMapping(
240                            filter, filterConfig, urlPatterns, dispatchers);
241    
242                    _filterMappings.add(filterMapping);
243            }
244    
245            protected void readLiferayFilterWebXML(
246                            ServletContext servletContext, String path)
247                    throws Exception {
248    
249                    InputStream inputStream = servletContext.getResourceAsStream(path);
250    
251                    if (inputStream == null) {
252                            return;
253                    }
254    
255                    Document document = SAXReaderUtil.read(inputStream, true);
256    
257                    Element rootElement = document.getRootElement();
258    
259                    List<Element> filterElements = rootElement.elements("filter");
260    
261                    for (Element filterElement : filterElements) {
262                            String filterName = filterElement.elementText("filter-name");
263                            String filterClassName = filterElement.elementText("filter-class");
264    
265                            Map<String, String> initParameterMap =
266                                    new HashMap<String, String>();
267    
268                            List<Element> initParamElements = filterElement.elements(
269                                    "init-param");
270    
271                            for (Element initParamElement : initParamElements) {
272                                    String name = initParamElement.elementText("param-name");
273                                    String value = initParamElement.elementText("param-value");
274    
275                                    initParameterMap.put(name, value);
276                            }
277    
278                            initFilter(
279                                    servletContext, filterName, filterClassName, initParameterMap);
280                    }
281    
282                    List<Element> filterMappingElements = rootElement.elements(
283                            "filter-mapping");
284    
285                    for (Element filterMappingElement : filterMappingElements) {
286                            String filterName = filterMappingElement.elementText("filter-name");
287    
288                            List<String> urlPatterns = new ArrayList<String>();
289    
290                            List<Element> urlPatternElements = filterMappingElement.elements(
291                                    "url-pattern");
292    
293                            for (Element urlPatternElement : urlPatternElements) {
294                                    urlPatterns.add(urlPatternElement.getTextTrim());
295                            }
296    
297                            List<String> dispatchers = new ArrayList<String>(4);
298    
299                            List<Element> dispatcherElements = filterMappingElement.elements(
300                                    "dispatcher");
301    
302                            for (Element dispatcherElement : dispatcherElements) {
303                                    String dispatcher =
304                                            dispatcherElement.getTextTrim().toUpperCase();
305    
306                                    dispatchers.add(dispatcher);
307                            }
308    
309                            initFilterMapping(filterName, urlPatterns, dispatchers);
310                    }
311            }
312    
313            private static Log _log = LogFactoryUtil.getLog(InvokerFilter.class);
314    
315            private Map<String, FilterConfig> _filterConfigs =
316                    new HashMap<String, FilterConfig>();
317            private List<FilterMapping> _filterMappings =
318                    new CopyOnWriteArrayList<FilterMapping>();
319            private Map<String, Filter> _filters = new HashMap<String, Filter>();
320            private List<InvokerFilter> _invokerFilters =
321                    new ArrayList<InvokerFilter>();
322    
323    }