001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1
003: * The contents of this file are subject to the Mozilla Public License Version
004: * 1.1 (the "License"); you may not use this file except in compliance with
005: * the License. You may obtain a copy of the License at
006: * http://www.mozilla.org/MPL/
007: *
008: * Software distributed under the License is distributed on an "AS IS" basis,
009: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
010: * for the specific language governing rights and limitations under the
011: * License.
012: *
013: * The Original Code is Riot.
014: *
015: * The Initial Developer of the Original Code is
016: * Neteye GmbH.
017: * Portions created by the Initial Developer are Copyright (C) 2006
018: * the Initial Developer. All Rights Reserved.
019: *
020: * Contributor(s):
021: * Felix Gnass [fgnass at neteye dot de]
022: *
023: * ***** END LICENSE BLOCK ***** */
024: package org.riotfamily.common.web.filter;
025:
026: import java.io.IOException;
027: import java.util.Arrays;
028:
029: import javax.servlet.FilterChain;
030: import javax.servlet.ServletContext;
031: import javax.servlet.ServletException;
032: import javax.servlet.http.HttpServletRequest;
033: import javax.servlet.http.HttpServletResponse;
034:
035: import org.springframework.core.OrderComparator;
036: import org.springframework.util.AntPathMatcher;
037: import org.springframework.web.filter.OncePerRequestFilter;
038: import org.springframework.web.util.UrlPathHelper;
039:
040: /**
041: * Servlet filter delegates the filtering to {@link FilterPlugin} beans.
042: * <p>
043: * In contrast to Spring's {@link org.springframework.web.filter.DelegatingFilterProxy}
044: * multiple targets are supported which are processed as a chain. Additionally
045: * the beans can be located in any BeanFactory that is aware of the
046: * ServletContext, not only the root ApplicationContext.
047: * <p>
048: * Riot uses this mechanism to allow modules to register servlet filters without
049: * having to modify the web.xml deployment descriptor.
050: *
051: * @see FilterPlugin
052: * @author Felix Gnass [fgnass at neteye dot de]
053: * @since 6.4
054: */
055: public final class PluginFilter extends OncePerRequestFilter {
056:
057: private static final String ATTRIBUTE_PREFIX = PluginFilter.class
058: .getName() + '.';
059:
060: private String[] exclude;
061:
062: private UrlPathHelper urlPathHelper = new UrlPathHelper();
063:
064: private AntPathMatcher pathMatcher = new AntPathMatcher();
065:
066: private OrderComparator orderComparator = new OrderComparator();
067:
068: private FilterPlugin[] plugins = new FilterPlugin[0];
069:
070: /**
071: * Sets Ant-style path patterns that should not be filtered.
072: */
073: public void setExclude(String[] exclude) {
074: this .exclude = exclude;
075: }
076:
077: protected void initFilterBean() throws ServletException {
078: getServletContext().setAttribute(
079: ATTRIBUTE_PREFIX + getFilterName(), this );
080: }
081:
082: synchronized void addPlugin(FilterPlugin plugin) {
083: int n = plugins.length;
084: FilterPlugin[] newPlugins = new FilterPlugin[n + 1];
085: System.arraycopy(plugins, 0, newPlugins, 0, n);
086: newPlugins[n++] = plugin;
087: Arrays.sort(newPlugins, orderComparator);
088: plugins = newPlugins;
089: }
090:
091: synchronized void removePlugin(FilterPlugin plugin) {
092: int n = plugins.length;
093: FilterPlugin[] newPlugins = new FilterPlugin[n - 1];
094: int j = 0;
095: for (int i = 0; i < n; i++) {
096: if (plugins[i] != plugin) {
097: newPlugins[j++] = plugins[i];
098: }
099: }
100: plugins = newPlugins;
101: }
102:
103: /**
104: * Skips the filter if the requested path matches one of the Ant-style
105: * pattern set via {@link #setExclude}.
106: */
107: protected boolean shouldNotFilter(HttpServletRequest request) {
108: if (exclude != null) {
109: String path = urlPathHelper
110: .getPathWithinApplication(request);
111: for (int i = 0; i < exclude.length; i++) {
112: if (pathMatcher.match(exclude[i], path)) {
113: return true;
114: }
115: }
116: }
117: return false;
118: }
119:
120: protected void doFilterInternal(HttpServletRequest request,
121: HttpServletResponse response, FilterChain filterChain)
122: throws ServletException, IOException {
123:
124: new PluginChain(filterChain, plugins).doFilter(request,
125: response);
126: }
127:
128: static PluginFilter getInstance(ServletContext servletContext,
129: String filterName) {
130:
131: return (PluginFilter) servletContext
132: .getAttribute(ATTRIBUTE_PREFIX + filterName);
133: }
134:
135: }
|