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