001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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                    int index = -1;
126    
127                    if (Validator.isNotNull(filterName)) {
128                            Filter filter = _filters.get(filterName);
129    
130                            if (filter != null) {
131                                    for (; i < _filterMappings.size(); i++) {
132                                            FilterMapping currentFilterMapping = _filterMappings.get(i);
133    
134                                            if (currentFilterMapping.getFilter() == filter) {
135                                                    index = i;
136    
137                                                    if (!after) {
138                                                            break;
139                                                    }
140                                            }
141                                    }
142                            }
143                            else {
144                                    after = false;
145                            }
146                    }
147    
148                    if (index == -1) {
149                            index = i;
150                    }
151    
152                    if (after) {
153                            index++;
154                    }
155    
156                    _filterMappings.add(index, filterMapping);
157    
158                    for (InvokerFilter invokerFilter : _invokerFilters) {
159                            invokerFilter.clearFilterChainsCache();
160                    }
161            }
162    
163            public void unregisterFilter(String filterName) {
164                    Filter filter = _filters.remove(filterName);
165    
166                    if (filter == null) {
167                            return;
168                    }
169    
170                    for (FilterMapping filterMapping : _filterMappings) {
171                            if (filterMapping.getFilter() == filter) {
172                                    unregisterFilterMapping(filterMapping);
173    
174                                    break;
175                            }
176                    }
177    
178                    _filterConfigs.remove(filterName);
179    
180                    try {
181                            filter.destroy();
182                    }
183                    catch (Exception e) {
184                            _log.error(e, e);
185                    }
186            }
187    
188            public void unregisterFilterMapping(FilterMapping filterMapping) {
189                    _filterMappings.remove(filterMapping);
190    
191                    for (InvokerFilter invokerFilter : _invokerFilters) {
192                            invokerFilter.clearFilterChainsCache();
193                    }
194            }
195    
196            protected void addInvokerFilter(InvokerFilter invokerFilter) {
197                    _invokerFilters.add(invokerFilter);
198            }
199    
200            protected InvokerFilterChain createInvokerFilterChain(
201                    HttpServletRequest request, Dispatcher dispatcher, String uri,
202                    FilterChain filterChain) {
203    
204                    InvokerFilterChain invokerFilterChain = new InvokerFilterChain(
205                            filterChain);
206    
207                    for (FilterMapping filterMapping : _filterMappings) {
208                            if (filterMapping.isMatch(request, dispatcher, uri)) {
209                                    Filter filter = filterMapping.getFilter();
210    
211                                    invokerFilterChain.addFilter(filter);
212                            }
213                    }
214    
215                    return invokerFilterChain;
216            }
217    
218            protected Filter getFilter(
219                    ServletContext servletContext, String filterClassName,
220                    FilterConfig filterConfig) {
221    
222                    ClassLoader pluginClassLoader = getPluginClassLoader(servletContext);
223    
224                    Thread currentThread = Thread.currentThread();
225    
226                    ClassLoader contextClassLoader = currentThread.getContextClassLoader();
227    
228                    try {
229                            if (contextClassLoader != pluginClassLoader) {
230                                    currentThread.setContextClassLoader(pluginClassLoader);
231                            }
232    
233                            Filter filter = (Filter)InstanceFactory.newInstance(
234                                    pluginClassLoader, filterClassName);
235    
236                            filter.init(filterConfig);
237    
238                            return filter;
239                    }
240                    catch (Exception e) {
241                            _log.error("Unable to initialize filter " + filterClassName, e);
242                    }
243                    finally {
244                            if (contextClassLoader != pluginClassLoader) {
245                                    currentThread.setContextClassLoader(contextClassLoader);
246                            }
247                    }
248    
249                    return null;
250            }
251    
252            protected ClassLoader getPluginClassLoader(ServletContext servletContext) {
253                    ClassLoader classLoader = (ClassLoader)servletContext.getAttribute(
254                            PluginContextListener.PLUGIN_CLASS_LOADER);
255    
256                    if (classLoader != null) {
257                            return classLoader;
258                    }
259    
260                    Thread currentThread = Thread.currentThread();
261    
262                    return currentThread.getContextClassLoader();
263            }
264    
265            protected void initFilter(
266                            ServletContext servletContext, String filterName,
267                            String filterClassName, Map<String, String> initParameterMap)
268                    throws Exception {
269    
270                    FilterConfig filterConfig = new InvokerFilterConfig(
271                            servletContext, filterName, initParameterMap);
272    
273                    Filter filter = getFilter(
274                            servletContext, filterClassName, filterConfig);
275    
276                    if (filter == null) {
277                            return;
278                    }
279    
280                    boolean filterEnabled = true;
281    
282                    if (filter instanceof LiferayFilter) {
283    
284                            // We no longer remove disabled filters because they can be enabled
285                            // at runtime by a hook. The performance difference is negligible
286                            // since most filters are assumed to be enabled.
287    
288                            //LiferayFilter liferayFilter = (LiferayFilter)filter;
289    
290                            //filterEnabled = liferayFilter.isFilterEnabled();
291                    }
292    
293                    if (filterEnabled) {
294                            _filterConfigs.put(filterName, filterConfig);
295                            _filters.put(filterName, filter);
296                    }
297                    else {
298                            if (filter instanceof PortalLifecycle) {
299                                    PortalLifecycle portalLifecycle = (PortalLifecycle)filter;
300    
301                                    PortalLifecycleUtil.removeDestroy(portalLifecycle);
302                            }
303    
304                            if (_log.isDebugEnabled()) {
305                                    _log.debug("Removing disabled filter " + filter.getClass());
306                            }
307                    }
308            }
309    
310            protected void initFilterMapping(
311                    String filterName, List<String> urlPatterns, List<String> dispatchers) {
312    
313                    Filter filter = _filters.get(filterName);
314    
315                    if (filter == null) {
316                            return;
317                    }
318    
319                    FilterConfig filterConfig = _filterConfigs.get(filterName);
320    
321                    if (filterConfig == null) {
322                            return;
323                    }
324    
325                    FilterMapping filterMapping = new FilterMapping(
326                            filter, filterConfig, urlPatterns, dispatchers);
327    
328                    _filterMappings.add(filterMapping);
329            }
330    
331            protected void readLiferayFilterWebXML(
332                            ServletContext servletContext, String path)
333                    throws Exception {
334    
335                    InputStream inputStream = servletContext.getResourceAsStream(path);
336    
337                    if (inputStream == null) {
338                            return;
339                    }
340    
341                    Document document = UnsecureSAXReaderUtil.read(inputStream, true);
342    
343                    Element rootElement = document.getRootElement();
344    
345                    List<Element> filterElements = rootElement.elements("filter");
346    
347                    for (Element filterElement : filterElements) {
348                            String filterName = filterElement.elementText("filter-name");
349                            String filterClassName = filterElement.elementText("filter-class");
350    
351                            Map<String, String> initParameterMap =
352                                    new HashMap<String, String>();
353    
354                            List<Element> initParamElements = filterElement.elements(
355                                    "init-param");
356    
357                            for (Element initParamElement : initParamElements) {
358                                    String name = initParamElement.elementText("param-name");
359                                    String value = initParamElement.elementText("param-value");
360    
361                                    initParameterMap.put(name, value);
362                            }
363    
364                            initFilter(
365                                    servletContext, filterName, filterClassName, initParameterMap);
366                    }
367    
368                    List<Element> filterMappingElements = rootElement.elements(
369                            "filter-mapping");
370    
371                    for (Element filterMappingElement : filterMappingElements) {
372                            String filterName = filterMappingElement.elementText("filter-name");
373    
374                            List<String> urlPatterns = new ArrayList<String>();
375    
376                            List<Element> urlPatternElements = filterMappingElement.elements(
377                                    "url-pattern");
378    
379                            for (Element urlPatternElement : urlPatternElements) {
380                                    urlPatterns.add(urlPatternElement.getTextTrim());
381                            }
382    
383                            List<String> dispatchers = new ArrayList<String>(4);
384    
385                            List<Element> dispatcherElements = filterMappingElement.elements(
386                                    "dispatcher");
387    
388                            for (Element dispatcherElement : dispatcherElements) {
389                                    String dispatcher = StringUtil.toUpperCase(
390                                            dispatcherElement.getTextTrim());
391    
392                                    dispatchers.add(dispatcher);
393                            }
394    
395                            initFilterMapping(filterName, urlPatterns, dispatchers);
396                    }
397            }
398    
399            private static Log _log = LogFactoryUtil.getLog(InvokerFilterHelper.class);
400    
401            private Map<String, FilterConfig> _filterConfigs =
402                    new HashMap<String, FilterConfig>();
403            private List<FilterMapping> _filterMappings =
404                    new CopyOnWriteArrayList<FilterMapping>();
405            private Map<String, Filter> _filters = new HashMap<String, Filter>();
406            private List<InvokerFilter> _invokerFilters =
407                    new ArrayList<InvokerFilter>();
408    
409    }