You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by lh...@apache.org on 2009/09/16 19:23:12 UTC
svn commit: r815896 - in
/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web: config/
filter/mgt/ servlet/
Author: lhazlewood
Date: Wed Sep 16 17:23:12 2009
New Revision: 815896
URL: http://svn.apache.org/viewvc?rev=815896&view=rev
Log:
Filter clean-up - refactored OncePerRequestFilter out to the new AbstractFilter and NamedFilter for clarity and to constrain OPRF to only already-filtered checks (overall functionality remains the same though). Modified WebConfiguration to add a getFilterChainResolver method and deprecated the old getFilterChain method (it still functions as expected for now). Further modifications will wait pending mailing list discussion 'Configuration: ShiroFilter vs WebConfiguration'. Also fixed various JavaDoc/spelling mistakes.
Added:
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AbstractFilter.java
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/NameableFilter.java
Modified:
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/IniWebConfiguration.java
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/WebConfiguration.java
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/mgt/FilterChainManager.java
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AdviceFilter.java
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/OncePerRequestFilter.java
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ServletContextSupport.java
incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java
Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/IniWebConfiguration.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/IniWebConfiguration.java?rev=815896&r1=815895&r2=815896&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/IniWebConfiguration.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/IniWebConfiguration.java Wed Sep 16 17:23:12 2009
@@ -24,6 +24,7 @@
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.util.CollectionUtils;
import org.apache.shiro.web.DefaultWebSecurityManager;
+import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -56,6 +57,7 @@
private PathMatchingFilterChainResolver resolver;
public IniWebConfiguration() {
+ this.resolver = new PathMatchingFilterChainResolver();
}
/**
@@ -84,6 +86,10 @@
return resolver.getChain(request, response, originalChain);
}
+ public FilterChainResolver getFilterChainResolver() {
+ return resolver;
+ }
+
/**
* Creates a new, uninitialized <code>SecurityManager</code> instance that will be used to build up
* the Shiro environment for the web application.
Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/WebConfiguration.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/WebConfiguration.java?rev=815896&r1=815895&r2=815896&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/WebConfiguration.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/config/WebConfiguration.java Wed Sep 16 17:23:12 2009
@@ -21,6 +21,10 @@
import org.apache.shiro.config.Configuration;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
/**
* A {@code WebConfiguration} configures Shiro components in a web-enabled application.
* <p/>
@@ -30,5 +34,25 @@
*
* @since 0.9
*/
-public interface WebConfiguration extends Configuration, FilterChainResolver {
+public interface WebConfiguration extends Configuration {
+
+ /**
+ * Returns the filter chain that should be executed for the given request, or {@code null} if the
+ * original chain should be used.
+ * <p/>
+ * This method allows a implementation to define arbitrary security {@link javax.servlet.Filter Filter}
+ * chains for any given request or URL pattern.
+ *
+ * @param request the incoming ServletRequest
+ * @param response the outgoing ServletResponse
+ * @param originalChain the original {@code FilterChain} intercepted by the ShiroFilter.
+ * @return the filter chain that should be executed for the given request, or {@code null} if the
+ * original chain should be used.
+ * @deprecated The WebConfiguration instance should return an instance of a FilterChainResolver via the
+ * {@link #getFilterChainResolver()} method instead.
+ */
+ @Deprecated
+ FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain);
+
+ FilterChainResolver getFilterChainResolver();
}
Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/mgt/FilterChainManager.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/mgt/FilterChainManager.java?rev=815896&r1=815895&r2=815896&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/mgt/FilterChainManager.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/filter/mgt/FilterChainManager.java Wed Sep 16 17:23:12 2009
@@ -116,7 +116,7 @@
* The {@code chainDefinition} method argument is expected to conform to the following format:
* <pre>
* filter1[optional_config1], filter2[optional_config2], ..., filterN[optional_configN]</pre>
- * Where
+ * where
* <ol>
* <li>{@code filterN} is the name of a filter previously
* {@link #addFilter(String, javax.servlet.Filter) registered} with the manager, and</li>
@@ -131,7 +131,7 @@
* <h3>Examples</h3>
* <pre>/account/** = authcBasic</pre>
* This example says "Create a filter named '{@code /account/**}' consisting of only the '{@code authcBasic}'
- * filter.". Also because the {@code authcBasic} filter does not need any path-specific
+ * filter". Also because the {@code authcBasic} filter does not need any path-specific
* config, it doesn't have any config brackets {@code []}.
* <p/>
* <pre>/remoting/** = authcBasic, roles[b2bClient], perms["remote:invoke:wan,lan"]</pre>
Added: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AbstractFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AbstractFilter.java?rev=815896&view=auto
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AbstractFilter.java (added)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AbstractFilter.java Wed Sep 16 17:23:12 2009
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.web.servlet;
+
+import org.apache.shiro.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.servlet.Filter;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+
+/**
+ * Base abstract Filter simplifying Filter initialization and {@link #getInitParam(String) access} to init parameters.
+ * Subclass initialization logic should be performed by overriding the {@link #onFilterConfigSet()} template method.
+ * FilterChain execution logic (the
+ * {@link #doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)} method
+ * is left to subclasses.
+ *
+ * @since 1.0
+ */
+public abstract class AbstractFilter extends ServletContextSupport implements Filter {
+
+ private static transient final Logger log = LoggerFactory.getLogger(AbstractFilter.class);
+
+ /**
+ * FilterConfig provided by the Servlet container at start-up.
+ */
+ protected FilterConfig filterConfig;
+
+ /**
+ * Returns the servlet container specified {@code FilterConfig} instance provided at
+ * {@link #init(javax.servlet.FilterConfig) startup}.
+ *
+ * @return the servlet container specified {@code FilterConfig} instance provided at start-up.
+ */
+ public FilterConfig getFilterConfig() {
+ return filterConfig;
+ }
+
+ /**
+ * Sets the FilterConfig <em>and</em> the {@code ServletContext} as attributes of this class for use by
+ * subclasses. That is:
+ * <pre>
+ * this.filterConfig = filterConfig;
+ * setServletContext(filterConfig.getServletContext());</pre>
+ *
+ * @param filterConfig the FilterConfig instance provided by the Servlet container at start-up.
+ */
+ public void setFilterConfig(FilterConfig filterConfig) {
+ this.filterConfig = filterConfig;
+ setServletContext(filterConfig.getServletContext());
+ }
+
+ /**
+ * Returns the value for the named {@code init-param}, or {@code null} if there was no {@code init-param}
+ * specified by that name.
+ *
+ * @param paramName the name of the {@code init-param}
+ * @return the value for the named {@code init-param}, or {@code null} if there was no {@code init-param}
+ * specified by that name.
+ */
+ protected String getInitParam(String paramName) {
+ FilterConfig config = getFilterConfig();
+ return StringUtils.clean(config.getInitParameter(paramName));
+ }
+
+ /**
+ * Sets the filter's {@link #setFilterConfig filterConfig} and then immediately calls
+ * {@link #onFilterConfigSet() onFilterConfigSet()} to trigger any processing a subclass might wish to perform.
+ *
+ * @param filterConfig the servlet container supplied FilterConfig instance.
+ * @throws javax.servlet.ServletException if {@link #onFilterConfigSet() onFilterConfigSet()} throws an Exception.
+ */
+ public final void init(FilterConfig filterConfig) throws ServletException {
+ setFilterConfig(filterConfig);
+ try {
+ onFilterConfigSet();
+ } catch (Exception e) {
+ if (e instanceof ServletException) {
+ throw (ServletException) e;
+ } else {
+ if (log.isErrorEnabled()) {
+ log.error("Unable to start Filter: [" + e.getMessage() + "].", e);
+ }
+ throw new ServletException(e);
+ }
+ }
+ }
+
+ /**
+ * Template method to be overridden by subclasses to perform initialization logic at start-up. The
+ * {@code ServletContext} and {@code FilterConfig} will be accessible
+ * (and non-{@code null}) at the time this method is invoked via the
+ * {@link #getServletContext() getServletContext()} and {@link #getFilterConfig() getFilterConfig()}
+ * methods respectively.
+ * <p/>
+ * {@code init-param} values may be conveniently obtained via the {@link #getInitParam(String)} method.
+ *
+ * @throws Exception if the subclass has an error upon initialization.
+ */
+ protected void onFilterConfigSet() throws Exception {
+ }
+
+ /**
+ * Default no-op implementation that can be overridden by subclasses for custom cleanup behavior.
+ */
+ public void destroy() {
+ }
+
+
+}
\ No newline at end of file
Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AdviceFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AdviceFilter.java?rev=815896&r1=815895&r2=815896&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AdviceFilter.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/AdviceFilter.java Wed Sep 16 17:23:12 2009
@@ -28,7 +28,7 @@
import java.io.IOException;
/**
- * A Servlet Filter that enables AOP-style "around" advice for a SerlvetRequest via
+ * A Servlet Filter that enables AOP-style "around" advice for a ServletRequest via
* {@link #preHandle(javax.servlet.ServletRequest, javax.servlet.ServletResponse) preHandle},
* {@link #postHandle(javax.servlet.ServletRequest, javax.servlet.ServletResponse) postHandle},
* and {@link #afterCompletion(javax.servlet.ServletRequest, javax.servlet.ServletResponse, Exception) afterCompletion}
@@ -45,14 +45,14 @@
private static final Logger log = LoggerFactory.getLogger(AdviceFilter.class);
/**
- * Returns <code>true</code> if the filter chain should be allowed to continue, <code>false</code> otherwise.
+ * Returns {@code true} if the filter chain should be allowed to continue, {@code false} otherwise.
* It is called before the chain is actually consulted/executed.
* <p/>
- * The default implementation returns <code>true</code> always and exists as a template method for subclasses.
+ * The default implementation returns {@code true} always and exists as a template method for subclasses.
*
* @param request the incoming ServletRequest
* @param response the outgoing ServletResponse
- * @return <code>true</code> if the filter chain should be allowed to continue, <code>false</code> otherwise.
+ * @return {@code true} if the filter chain should be allowed to continue, {@code false} otherwise.
* @throws Exception if there is any error.
*/
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
@@ -73,12 +73,13 @@
* @param response the outgoing ServletResponse
* @throws Exception if an error occurs.
*/
+ @SuppressWarnings({"UnusedDeclaration"})
protected void postHandle(ServletRequest request, ServletResponse response) throws Exception {
}
/**
- * Called in all cases in a <code>finally</code> block even if {@link #preHandle preHandle} returns
- * <code>false</code> or if an exception is thrown during filter chain processing. Can be used for resource
+ * Called in all cases in a {@code finally} block even if {@link #preHandle preHandle} returns
+ * {@code false} or if an exception is thrown during filter chain processing. Can be used for resource
* cleanup if so desired.
* <p/>
* The default implementation does nothing (no-op) and exists as a template method for subclasses.
@@ -86,10 +87,11 @@
* @param request the incoming ServletRequest
* @param response the outgoing ServletResponse
* @param exception any exception thrown during {@link #preHandle preHandle}, {@link #executeChain executeChain},
- * or {@link #postHandle postHandle} execution, or <code>null</code> if no exception was thrown
+ * or {@link #postHandle postHandle} execution, or {@code null} if no exception was thrown
* (i.e. the chain processed successfully).
* @throws Exception if an error occurs.
*/
+ @SuppressWarnings({"UnusedDeclaration"})
public void afterCompletion(ServletRequest request, ServletResponse response, Exception exception) throws Exception {
}
@@ -120,7 +122,6 @@
* @throws ServletException if a servlet-related error occurs
* @throws IOException if an IO error occurs
*/
- @SuppressWarnings({"ThrowFromFinallyBlock"})
public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException {
@@ -130,7 +131,7 @@
boolean continueChain = preHandle(request, response);
if (log.isTraceEnabled()) {
- log.trace("Invked preHandle method. Continuing chain?: [" + continueChain + "]");
+ log.trace("Invoked preHandle method. Continuing chain?: [" + continueChain + "]");
}
if (continueChain) {
@@ -150,7 +151,7 @@
}
/**
- * Executes cleanup logic in the <code>finally</code> code block in the
+ * Executes cleanup logic in the {@code finally} code block in the
* {@link #doFilterInternal(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) doFilterInternal}
* implementation.
* <p/>
@@ -158,12 +159,12 @@
* {@link #afterCompletion(javax.servlet.ServletRequest, javax.servlet.ServletResponse, Exception) afterCompletion}
* as well as handles any exceptions properly.
*
- * @param request the incoming <code>ServletRequest</code>
- * @param response the outgoing <code>ServletResponse</code>
- * @param existing any exception that might have occurred while executing the <code>FilterChain</code> or
- * pre or post advice, or <code>null</code> if the pre/chain/post excution did not throw an <code>Exception</code>.
- * @throws ServletException if any exception other than an <code>IOException</code> is thrown.
- * @throws IOException if the pre/chain/post execution throw an <code>IOException</code>
+ * @param request the incoming {@code ServletRequest}
+ * @param response the outgoing {@code ServletResponse}
+ * @param existing any exception that might have occurred while executing the {@code FilterChain} or
+ * pre or post advice, or {@code null} if the pre/chain/post execution did not throw an {@code Exception}.
+ * @throws ServletException if any exception other than an {@code IOException} is thrown.
+ * @throws IOException if the pre/chain/post execution throw an {@code IOException}
*/
protected void cleanup(ServletRequest request, ServletResponse response, Exception existing)
throws ServletException, IOException {
@@ -176,6 +177,9 @@
} catch (Exception e) {
if (exception == null) {
exception = e;
+ } else {
+ log.debug("afterCompletion implementation threw an exception. This will be ignored to " +
+ "allow the original source exception to be propagated.", e);
}
}
if (exception != null) {
@@ -184,10 +188,13 @@
} else if (exception instanceof IOException) {
throw (IOException) exception;
} else {
- String msg = "Filter execution resulted in an unexpected Exception " +
- "(not IOException or ServletException as the Filter api recommends). " +
- "Wrapping in ServletException and propagating.";
- throw new ServletException(msg, exception);
+ if (log.isDebugEnabled()) {
+ String msg = "Filter execution resulted in an unexpected Exception " +
+ "(not IOException or ServletException as the Filter API recommends). " +
+ "Wrapping in ServletException and propagating.";
+ log.debug(msg);
+ }
+ throw new ServletException(exception);
}
}
}
Added: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/NameableFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/NameableFilter.java?rev=815896&view=auto
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/NameableFilter.java (added)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/NameableFilter.java Wed Sep 16 17:23:12 2009
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.shiro.web.servlet;
+
+import org.apache.shiro.util.Nameable;
+
+import javax.servlet.FilterConfig;
+
+/**
+ * Allows a filter to be named via JavaBeans-compatible
+ * {@link #getName()}/{@link #setName(String)} methods. If no name is specified, the name of the filter will
+ * default to the name given to it in {@code web.xml} (the {@code FilterConfig}'s
+ * {@link javax.servlet.FilterConfig#getFilterName() filterName}).
+ *
+ * @since 1.0
+ */
+public abstract class NameableFilter extends AbstractFilter implements Nameable {
+
+ /**
+ * The name of this filter, unique within an application.
+ */
+ private String name;
+
+ /**
+ * Returns the filter's name.
+ * <p/>
+ * Unless overridden by calling the {@link #setName(String) setName(String)} method, this value defaults to the
+ * filter name as specified by the servlet container at start-up:
+ * <pre>
+ * this.name = {@link #getFilterConfig() getFilterConfig()}.{@link javax.servlet.FilterConfig#getFilterName() getName()};</pre>
+ *
+ * @return the filter name, or {@code null} if none available
+ * @see javax.servlet.GenericServlet#getServletName()
+ * @see javax.servlet.FilterConfig#getFilterName()
+ */
+ protected String getName() {
+ if (this.name == null) {
+ FilterConfig config = getFilterConfig();
+ if (config != null) {
+ this.name = config.getFilterName();
+ }
+ }
+
+ return this.name;
+ }
+
+ /**
+ * Sets the filter's name.
+ * <p/>
+ * Unless overridden by calling this method, this value defaults to the filter name as specified by the
+ * servlet container at start-up:
+ * <pre>
+ * this.name = {@link #getFilterConfig() getFilterConfig()}.{@link javax.servlet.FilterConfig#getFilterName() getName()};</pre>
+ *
+ * @param name the name of the filter.
+ */
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns a StringBuilder instance with the {@link #getName() name}, or if the name is {@code null}, just the
+ * {@code super.toStringBuilder()} instance.
+ *
+ * @return a StringBuilder instance to use for appending String data that will eventually be returned from a
+ * {@code toString()} invocation.
+ */
+ protected StringBuilder toStringBuilder() {
+ String name = getName();
+ if (name == null) {
+ return super.toStringBuilder();
+ } else {
+ StringBuilder sb = new StringBuilder();
+ sb.append(name);
+ return sb;
+ }
+ }
+
+}
Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/OncePerRequestFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/OncePerRequestFilter.java?rev=815896&r1=815895&r2=815896&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/OncePerRequestFilter.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/OncePerRequestFilter.java Wed Sep 16 17:23:12 2009
@@ -18,11 +18,13 @@
*/
package org.apache.shiro.web.servlet;
-import org.apache.shiro.util.Nameable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.servlet.*;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import java.io.IOException;
@@ -31,18 +33,18 @@
* on any servlet container. It provides a {@link #doFilterInternal}
* method with HttpServletRequest and HttpServletResponse arguments.
* <p/>
- * <p>The {@link #getAlreadyFilteredAttributeName} method determines how
+ * The {@link #getAlreadyFilteredAttributeName} method determines how
* to identify that a request is already filtered. The default implementation
* is based on the configured name of the concrete filter instance.
* <p/>
- * <p><b>NOTE</b> This class was borrowed from the Spring framework, and as such,
+ * <b>NOTE</b> This class was borrowed from the Spring framework, and as such,
* all copyright notices and author names have remained in tact.
*
* @author Les Hazlewood
* @author Juergen Hoeller
* @since 0.1
*/
-public abstract class OncePerRequestFilter extends ServletContextSupport implements Filter, Nameable {
+public abstract class OncePerRequestFilter extends NameableFilter {
/**
* Private internal log instance.
@@ -57,113 +59,7 @@
public static final String ALREADY_FILTERED_SUFFIX = ".FILTERED";
/**
- * FilterConfig provided by the Servlet container at startup.
- */
- protected FilterConfig filterConfig;
-
- /**
- * The name of this filter, unique within an application.
- */
- private String name;
-
- /**
- * Returns the servlet container specified <code>FilterConfig</code> instance provided at
- * {@link #init(javax.servlet.FilterConfig) startup}.
- *
- * @return the servlet container specified <code>FilterConfig</code> instance provided at startup.
- */
- public FilterConfig getFilterConfig() {
- return filterConfig;
- }
-
- /**
- * Sets the FilterConfig <em>and</em> the <code>ServletContext</code> as attributes of this class for use by
- * subclasses. That is:
- * <p/>
- * <code>this.filterConfig = filterConfig;<br/>
- * setServletContext(filterConfig.getServletContext());</code>
- *
- * @param filterConfig the FilterConfig instance provided by the Servlet container at startup.
- */
- public void setFilterConfig(FilterConfig filterConfig) {
- this.filterConfig = filterConfig;
- setServletContext(filterConfig.getServletContext());
- }
-
- /**
- * Returns the name of this filter.
- * <p/>
- * Unless overridden by calling the {@link #setName(String) setName(String)} method, this value defaults to the
- * filter name as specified by the servlet container at startup:
- * <p/>
- * <code>this.name = {@link #getFilterConfig() getFilterConfig()}.{@link FilterConfig#getFilterName() getName()};</code>
- *
- * @return the filter name, or <code>null</code> if none available
- * @see javax.servlet.GenericServlet#getServletName()
- * @see javax.servlet.FilterConfig#getFilterName()
- */
- protected String getName() {
- if (this.name == null) {
- FilterConfig config = getFilterConfig();
- if (config != null) {
- this.name = config.getFilterName();
- }
- }
-
- return this.name;
- }
-
- /**
- * Sets the filter's name.
- * <p/>
- * Unless overridden by calling this method, this value defaults to the filter name as specified by the
- * servlet container at startup:
- * <p/>
- * <code>this.name = {@link #getFilterConfig() getFilterConfig()}.{@link FilterConfig#getFilterName() getName()};</code>
- *
- * @param name the name of the filter.
- */
- public void setName(String name) {
- this.name = name;
- }
-
- /**
- * Sets the filter's {@link #setFilterConfig filterConfig} and then immediately calls
- * {@link #onFilterConfigSet() onFilterConfigSet()} to trigger any processing a subclass might wish to perform.
- *
- * @param filterConfig the servlet container supplied FilterConfig instance.
- * @throws ServletException if {@link #onFilterConfigSet() onFilterConfigSet()} throws an Exception.
- */
- public final void init(FilterConfig filterConfig) throws ServletException {
- setFilterConfig(filterConfig);
- try {
- onFilterConfigSet();
- } catch (Exception e) {
- if (e instanceof ServletException) {
- throw (ServletException) e;
- } else {
- if (log.isErrorEnabled()) {
- log.error("Unable to start Filter: [" + e.getMessage() + "].", e);
- }
- throw new ServletException(e);
- }
- }
- }
-
- /**
- * Template method to be overridden by subclasses to perform initialization logic at startup. The
- * <code>ServletContext</code> and <code>FilterConfig</code> will be accessible
- * (and non-<code>null</code>) at the time this method is invoked via the
- * {@link #getServletContext() getServletContext()} and {@link #getFilterConfig() getFilterConfig()}
- * methods respectively.
- *
- * @throws Exception if the subclass has an error upon initialization.
- */
- protected void onFilterConfigSet() throws Exception {
- }
-
- /**
- * This <code>doFilter</code> implementation stores a request attribute for
+ * This {@code doFilter} implementation stores a request attribute for
* "already filtered", proceeding without filtering again if the
* attribute is already there.
*
@@ -173,7 +69,6 @@
*/
public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
-
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
if (request.getAttribute(alreadyFilteredAttributeName) != null || shouldNotFilter(request)) {
log.trace("Filter '{}' already executed. Proceeding without invoking this filter.", getName());
@@ -190,7 +85,7 @@
/**
* Return name of the request attribute that identifies that a request has already been filtered.
* <p/>
- * The default implementation takes the configured {@link #getName() name} and appends ".FILTERED".
+ * The default implementation takes the configured {@link #getName() name} and appends "{@code .FILTERED}".
* If the filter is not fully initialized, it falls back to the implementation's class name.
*
* @return the name of the request attribute that identifies that a request has already been filtered.
@@ -221,50 +116,16 @@
/**
- * Same contract as for <code>doFilter</code>, but guaranteed to be just invoked once per request.
+ * Same contract as for
+ * {@link #doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)},
+ * but guaranteed to be invoked only once per request.
*
* @param request incoming {@code ServletRequest}
* @param response outgoing {@code ServletResponse}
* @param chain the {@code FilterChain} to execute
* @throws ServletException if there is a problem processing the request
- * @throws IOException if there is an IO problem processing the request
+ * @throws IOException if there is an I/O problem processing the request
*/
protected abstract void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain)
throws ServletException, IOException;
-
- /**
- * Default no-op implementation that can be overridden by subclasses for custom cleanup behavior.
- */
- public void destroy() {
- }
-
- /**
- * It is highly recommended not to override this method directly, and instead override the
- * {@link #toStringBuilder() toStringBuilder()} method, a better-performing alternative.
- *
- * @return the String representation of this instance.
- */
- @Override
- public String toString() {
- return toStringBuilder().toString();
- }
-
- /**
- * Same concept as {@link #toString() toString()}, but returns a {@link StringBuilder} instance instead.
- * Overriding subclasses would usually call <code>super.toStringBuilder()</code> and use the returned instance
- * to append to instead of creating a new StringBuilder.
- *
- * @return a StringBuilder instance to use for appending String data that will eventually be returned from a
- * {@code toString()} invocation.
- */
- protected StringBuilder toStringBuilder() {
- StringBuilder sb = new StringBuilder();
- String name = getName();
- if (name == null) {
- sb.append(super.toString());
- } else {
- sb.append(name);
- }
- return sb;
- }
}
Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ServletContextSupport.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ServletContextSupport.java?rev=815896&r1=815895&r2=815896&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ServletContextSupport.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ServletContextSupport.java Wed Sep 16 17:23:12 2009
@@ -39,11 +39,12 @@
this.servletContext = servletContext;
}
+ @SuppressWarnings({"UnusedDeclaration"})
protected String getContextInitParam(String paramName) {
return getServletContext().getInitParameter(paramName);
}
- private ServletContext getServletContextNullCheck() {
+ private ServletContext getRequiredServletContext() {
ServletContext servletContext = getServletContext();
if (servletContext == null) {
String msg = "ServletContext property must be set via the setServletContext method.";
@@ -52,27 +53,42 @@
return servletContext;
}
- protected void setAttribute(String key, Object value) {
- getServletContextNullCheck().setAttribute(key, value);
- }
-
- protected Object getAttribute(String key) {
- return getServletContextNullCheck().getAttribute(key);
- }
-
- protected void removeAttribute(String key) {
- getServletContextNullCheck().removeAttribute(key);
- }
-
- protected void bind(String name, String key, Object value) {
+ @SuppressWarnings({"UnusedDeclaration"})
+ protected void setContextAttribute(String key, Object value) {
if (value == null) {
- throw new IllegalArgumentException(name + " argument cannot be null.");
- }
- if (getAttribute(key) != null) {
- String msg = name + " already bound to ServletContext. Please check your configuration to ensure " +
- "you don't have mutliple SecurityManager Loaders configured (listener, servlet, etc).";
- throw new IllegalStateException(msg);
+ removeContextAttribute(key);
+ } else {
+ getRequiredServletContext().setAttribute(key, value);
}
- setAttribute(key, value);
+ }
+
+ @SuppressWarnings({"UnusedDeclaration"})
+ protected Object getContextAttribute(String key) {
+ return getRequiredServletContext().getAttribute(key);
+ }
+
+ protected void removeContextAttribute(String key) {
+ getRequiredServletContext().removeAttribute(key);
+ }
+
+ /**
+ * It is highly recommended not to override this method directly, and instead override the
+ * {@link #toStringBuilder() toStringBuilder()} method, a better-performing alternative.
+ *
+ * @return the String representation of this instance.
+ */
+ @Override
+ public String toString() {
+ return toStringBuilder().toString();
+ }
+
+ /**
+ * Same concept as {@link #toString() toString()}, but returns a {@link StringBuilder} instance instead.
+ *
+ * @return a StringBuilder instance to use for appending String data that will eventually be returned from a
+ * {@code toString()} invocation.
+ */
+ protected StringBuilder toStringBuilder() {
+ return new StringBuilder(super.toString());
}
}
Modified: incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java
URL: http://svn.apache.org/viewvc/incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java?rev=815896&r1=815895&r2=815896&view=diff
==============================================================================
--- incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java (original)
+++ incubator/shiro/trunk/web/src/main/java/org/apache/shiro/web/servlet/ShiroFilter.java Wed Sep 16 17:23:12 2009
@@ -19,6 +19,7 @@
package org.apache.shiro.web.servlet;
import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.shiro.SecurityUtils;
import org.apache.shiro.config.Configuration;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.mgt.SecurityManager;
@@ -26,19 +27,22 @@
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ClassUtils;
import org.apache.shiro.util.LifecycleUtils;
-import static org.apache.shiro.util.StringUtils.clean;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.util.ThreadState;
import org.apache.shiro.web.DefaultWebSecurityManager;
import org.apache.shiro.web.WebUtils;
import org.apache.shiro.web.config.IniWebConfiguration;
import org.apache.shiro.web.config.WebConfiguration;
+import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.subject.WebSubject;
import org.apache.shiro.web.subject.support.WebSubjectThreadState;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.servlet.*;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
@@ -244,6 +248,9 @@
// Reference to the security manager used by this filter
protected SecurityManager securityManager;
+ // Used to determine which chain should handle an incoming request/response
+ private FilterChainResolver filterChainResolver;
+
public ShiroFilter() {
this.configClassName = IniWebConfiguration.class.getName();
}
@@ -260,28 +267,38 @@
return securityManager;
}
- protected void setSecurityManager(org.apache.shiro.mgt.SecurityManager sm) {
+ protected void setSecurityManager(SecurityManager sm) {
this.securityManager = sm;
}
+ public FilterChainResolver getFilterChainResolver() {
+ return filterChainResolver;
+ }
+
+ public void setFilterChainResolver(FilterChainResolver filterChainResolver) {
+ this.filterChainResolver = filterChainResolver;
+ }
+
protected void onFilterConfigSet() throws Exception {
applyInitParams();
WebConfiguration config = configure();
setConfiguration(config);
-
- // Retrieve and store a reference to the security manager
- SecurityManager securityManager = ensureSecurityManager(config);
- setSecurityManager(securityManager);
+ ensureSecurityManager(config);
+ applyFilterChainResolver(config);
}
/**
- * Retrieves the security manager for the given configuration.
+ * Ensures a SecurityManager exists, and if not, creates one automatically and ensures it is available for
+ * use during requests.
*
* @param config the configuration for this filter.
- * @return the security manager that this filter should use.
*/
- protected SecurityManager ensureSecurityManager(Configuration config) {
- SecurityManager securityManager = config.getSecurityManager();
+ protected void ensureSecurityManager(Configuration config) {
+ SecurityManager securityManager = getSecurityManager();
+ boolean existing = securityManager != null;
+ if (!existing && config != null) {
+ securityManager = config.getSecurityManager();
+ }
// If the config doesn't return a security manager, build one by default.
if (securityManager == null) {
@@ -292,13 +309,24 @@
securityManager = new DefaultWebSecurityManager();
}
- return securityManager;
+ if (!existing) {
+ setSecurityManager(securityManager);
+ }
+ }
+
+ protected void applyFilterChainResolver(WebConfiguration config) {
+ FilterChainResolver resolver = getFilterChainResolver();
+ if (resolver == null && config != null) {
+ resolver = config.getFilterChainResolver();
+ if (resolver != null) {
+ setFilterChainResolver(resolver);
+ }
+ }
}
protected void applyInitParams() {
- FilterConfig config = getFilterConfig();
- String configCN = clean(config.getInitParameter(CONFIG_CLASS_NAME_INIT_PARAM_NAME));
+ String configCN = getInitParam(CONFIG_CLASS_NAME_INIT_PARAM_NAME);
if (configCN != null) {
if (ClassUtils.isAvailable(configCN)) {
this.configClassName = configCN;
@@ -310,17 +338,17 @@
}
}
- this.config = clean(config.getInitParameter(CONFIG_INIT_PARAM_NAME));
- this.configUrl = clean(config.getInitParameter(CONFIG_URL_INIT_PARAM_NAME));
+ this.config = getInitParam(CONFIG_INIT_PARAM_NAME);
+ this.configUrl = getInitParam(CONFIG_URL_INIT_PARAM_NAME);
}
protected WebConfiguration configure() {
- WebConfiguration conf = (WebConfiguration) ClassUtils.newInstance(this.configClassName);
- applyFilterConfig(conf);
- applyUrlConfig(conf);
- applyEmbeddedConfig(conf);
- LifecycleUtils.init(conf);
- return conf;
+ WebConfiguration webConfiguration = (WebConfiguration) ClassUtils.newInstance(this.configClassName);
+ applyFilterConfig(webConfiguration);
+ applyUrlConfig(webConfiguration);
+ applyEmbeddedConfig(webConfiguration);
+ LifecycleUtils.init(webConfiguration);
+ return webConfiguration;
}
protected void applyFilterConfig(WebConfiguration conf) {
@@ -352,7 +380,7 @@
String msg = "The 'config' filter param was specified, but there is no " +
"'setConfig(String)' method on the Configuration instance [" + conf + "]. If you do " +
"not require the 'config' filter param, please comment it out, or if you do need it, " +
- "please ensure your Configuration instance has a 'setConfig(String)' method to receive it.";
+ "please ensure your Configuration class has a 'setConfig(String)' method to receive it.";
throw new ConfigurationException(msg);
}
} catch (Exception e) {
@@ -373,7 +401,7 @@
String msg = "The 'configUrl' filter param was specified, but there is no " +
"'setConfigUrl(String)' method on the Configuration instance [" + conf + "]. If you do " +
"not require the 'configUrl' filter param, please comment it out, or if you do need it, " +
- "please ensure your Configuration instance has a 'setConfigUrl(String)' method to receive it.";
+ "please ensure your Configuration class has a 'setConfigUrl(String)' method to receive it.";
throw new ConfigurationException(msg);
}
} catch (Exception e) {
@@ -401,7 +429,7 @@
}
/**
- * 'Prepare's the {@code ServletRequest} instance that will be passed to the {@code FilterChain} for request
+ * Prepares the {@code ServletRequest} instance that will be passed to the {@code FilterChain} for request
* processing.
* <p/>
* If the {@code ServletRequest} is an instance of {@link HttpServletRequest}, the value returned from this method
@@ -439,7 +467,7 @@
}
/**
- * 'Prepare's the {@code ServletResponse} instance that will be passed to the {@code FilterChain} for request
+ * Prepares the {@code ServletResponse} instance that will be passed to the {@code FilterChain} for request
* processing.
* <p/>
* This implementation delegates to {@link #wrapServletRequest(javax.servlet.http.HttpServletRequest)}
@@ -478,7 +506,7 @@
* {@link #unbind} method must be called in a {@code finally} block to ensure that the thread remains clean even
* in the event of an exception thrown while processing the request. This class's
* {@link #doFilterInternal(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)}
- * method implement does indeed perform this.
+ * method implementation does indeed function this way.
*
* @param request the incoming ServletRequest
* @param response the outgoing ServletResponse
@@ -527,7 +555,7 @@
@SuppressWarnings({"UnusedDeclaration"})
protected void updateSessionLastAccessTime(ServletRequest request, ServletResponse response) {
if (!isHttpSessions()) { //'native' sessions
- Subject subject = getSecurityManager().getSubject();
+ Subject subject = SecurityUtils.getSubject();
//Subject should never _ever_ be null, but just in case:
if (subject != null) {
Session session = subject.getSession(false);
@@ -593,13 +621,12 @@
* <p/>
* The {@code origChain} argument is the
* original {@code FilterChain} supplied by the Servlet Container, but it may be modified to provide
- * more behavior by appending further chains according to the Shiro configuration.
+ * more behavior by pre-pending further chains according to the Shiro configuration.
* <p/>
* This implementation returns the chain that will actually be executed by acquiring the chain from a
- * <code>{@link #getConfiguration() getConfiguration()}.{@link org.apache.shiro.web.config.WebConfiguration#getChain getChain}(request,response,origChain)</code>
- * method call. The configuration itself determines which chain to execute, typically based on URL configuration.
- * If no chain is returned from this method call (returns {@code null}), then the {@code origChain}
- * will be returned by default.
+ * {@link #getFilterChainResolver() filterChainResolver}. The resolver determines exactly which chain to
+ * execute, typically based on URL configuration. If no chain is returned from the resolver call
+ * (returns {@code null}), then the {@code origChain} will be returned by default.
*
* @param request the incoming ServletRequest
* @param response the outgoing ServletResponse
@@ -608,13 +635,26 @@
* @since 1.0
*/
protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {
- FilterChain chain = getConfiguration().getChain(request, response, origChain);
- if (chain == null) {
- chain = origChain;
- log.trace("No security filter chain configured for the current request. Using default.");
+ FilterChain chain = origChain;
+ FilterChain resolved = null;
+ FilterChainResolver resolver = getFilterChainResolver();
+ if (resolver != null) {
+ resolved = resolver.getChain(request, response, origChain);
} else {
- log.trace(" Using configured filter chain for the current request.");
+ log.trace("No FilterChainResolver configured. Attempting (deprecated) WebConfiguration resolution.");
+ WebConfiguration config = getConfiguration();
+ if (config != null) {
+ //noinspection deprecation
+ resolved = config.getChain(request, response, origChain);
+ }
}
+ if (resolved != null) {
+ log.trace("Resolved a configured FilterChain for the current request.");
+ chain = resolved;
+ } else {
+ log.trace("No FilterChain configured for the current request. Using the default.");
+ }
+
return chain;
}
@@ -626,7 +666,6 @@
* to allow the application's Shiro configuration to determine exactly how the chain should execute. The resulting
* value from that call is then executed directly by calling the returned {@code FilterChain}'s
* {@link FilterChain#doFilter doFilter} method. That is:
- * <p/>
* <pre>
* FilterChain chain = {@link #getExecutionChain}(request, response, origChain);
* chain.{@link FilterChain#doFilter doFilter}(request,response);</pre>