Author: rgielen
Date: Sat Apr 25 13:49:50 2009
New Revision: 768529

URL: http://svn.apache.org/viewvc?rev=768529&view=rev
Log:
WW-3017 - Making it possible to have a configurable list of uri-patterns 
telling struts not to handle the request
- applied patch provided by Andreas Joseph Krogh
- made some refactoring to eliminate duplicate code and unneeded method calls
- added integration test

Modified:
    
struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java
    
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/InitOperations.java
    
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/PrepareOperations.java
    
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsExecuteFilter.java
    
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareAndExecuteFilter.java
    
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareFilter.java
    
struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ng/StrutsPrepareAndExecuteFilterIntegrationTest.java

Modified: 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java
URL: 
http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java?rev=768529&r1=768528&r2=768529&view=diff
==============================================================================
--- 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java 
(original)
+++ 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/StrutsConstants.java 
Sat Apr 25 13:49:50 2009
@@ -44,6 +44,9 @@
     /** The URL extension to use to determine if the request is meant for a 
Struts action */
     public static final String STRUTS_ACTION_EXTENSION = 
"struts.action.extension";
 
+       /** Comma separated list of patterns (java.util.regex.Pattern) to be 
excluded from Struts2-processing */
+       public static final String STRUTS_ACTION_EXCLUDE_PATTERN = 
"struts.action.exclude_pattern";
+
     /** Whether to use the alterative syntax for the tags or not */
     public static final String STRUTS_TAG_ALTSYNTAX = "struts.tag.altSyntax";
 

Modified: 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/InitOperations.java
URL: 
http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/InitOperations.java?rev=768529&r1=768528&r2=768529&view=diff
==============================================================================
--- 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/InitOperations.java
 (original)
+++ 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/InitOperations.java
 Sat Apr 25 13:49:50 2009
@@ -25,10 +25,10 @@
 import org.apache.struts2.dispatcher.Dispatcher;
 import org.apache.struts2.dispatcher.StaticContentLoader;
 import org.apache.struts2.util.ClassLoaderUtils;
+import org.apache.struts2.StrutsConstants;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Iterator;
+import java.util.*;
+import java.util.regex.Pattern;
 
 /**
  * Contains initialization operations
@@ -41,20 +41,20 @@
     /**
      * Initializes the internal Struts logging
      */
-    public void initLogging(HostConfig filterConfig) {
+    public void initLogging( HostConfig filterConfig ) {
         String factoryName = filterConfig.getInitParameter("loggerFactory");
         if (factoryName != null) {
             try {
                 Class cls = ClassLoaderUtils.loadClass(factoryName, 
this.getClass());
                 LoggerFactory fac = (LoggerFactory) cls.newInstance();
                 LoggerFactory.setLoggerFactory(fac);
-            } catch (InstantiationException e) {
+            } catch ( InstantiationException e ) {
                 System.err.println("Unable to instantiate logger factory: " + 
factoryName + ", using default");
                 e.printStackTrace();
-            } catch (IllegalAccessException e) {
+            } catch ( IllegalAccessException e ) {
                 System.err.println("Unable to access logger factory: " + 
factoryName + ", using default");
                 e.printStackTrace();
-            } catch (ClassNotFoundException e) {
+            } catch ( ClassNotFoundException e ) {
                 System.err.println("Unable to locate logger factory class: " + 
factoryName + ", using default");
                 e.printStackTrace();
             }
@@ -64,7 +64,7 @@
     /**
      * Creates and initializes the dispatcher
      */
-    public Dispatcher initDispatcher(HostConfig filterConfig) {
+    public Dispatcher initDispatcher( HostConfig filterConfig ) {
         Dispatcher dispatcher = createDispatcher(filterConfig);
         dispatcher.init();
         return dispatcher;
@@ -73,7 +73,7 @@
     /**
      * Initializes the static content loader with the filter configuration
      */
-    public StaticContentLoader initStaticContentLoader(HostConfig 
filterConfig, Dispatcher dispatcher) {
+    public StaticContentLoader initStaticContentLoader( HostConfig 
filterConfig, Dispatcher dispatcher ) {
         StaticContentLoader loader = 
dispatcher.getContainer().getInstance(StaticContentLoader.class);
         loader.setHostConfig(filterConfig);
         return loader;
@@ -81,6 +81,7 @@
 
     /**
      * @return The dispatcher on the thread.
+     *
      * @throws IllegalStateException If there is no dispatcher available
      */
     public Dispatcher findDispatcherOnThread() {
@@ -92,11 +93,11 @@
     }
 
     /**
-     * Create a {...@link Dispatcher} 
+     * Create a {...@link Dispatcher}
      */
-    private Dispatcher createDispatcher(HostConfig filterConfig) {
+    private Dispatcher createDispatcher( HostConfig filterConfig ) {
         Map<String, String> params = new HashMap<String, String>();
-        for (Iterator e = filterConfig.getInitParameterNames(); e.hasNext();) {
+        for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext(); 
) {
             String name = (String) e.next();
             String value = filterConfig.getInitParameter(name);
             params.put(name, value);
@@ -107,4 +108,31 @@
     public void cleanup() {
         ActionContext.setContext(null);
     }
+
+    /**
+     * Extract a list of patterns to exclude from request filtering
+     *
+     * @param dispatcher The dispatcher to check for exclude pattern 
configuration
+     *
+     * @return a List of Patterns for request to exclude if apply, or 
<tt>null</tt>
+     *
+     * @see org.apache.struts2.StrutsConstants#STRUTS_ACTION_EXCLUDE_PATTERN
+     */
+    public List<Pattern> buildExcludedPatternsList( Dispatcher dispatcher ) {
+        return 
buildExcludedPatternsList(dispatcher.getContainer().getInstance(String.class, 
StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN));
+    }
+            
+    private List<Pattern> buildExcludedPatternsList( String patterns ) {
+        if (null != patterns && patterns.trim().length() != 0) {
+            List<Pattern> list = new ArrayList<Pattern>();
+            String[] tokens = patterns.split(",");
+            for ( String token : tokens ) {
+                list.add(Pattern.compile(token.trim()));
+            }
+            return Collections.unmodifiableList(list);
+        } else {
+            return null;
+        }
+    }
+
 }

Modified: 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/PrepareOperations.java
URL: 
http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/PrepareOperations.java?rev=768529&r1=768528&r2=768529&view=diff
==============================================================================
--- 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/PrepareOperations.java
 (original)
+++ 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/PrepareOperations.java
 Sat Apr 25 13:49:50 2009
@@ -24,6 +24,7 @@
 import org.apache.struts2.dispatcher.mapper.ActionMapping;
 import org.apache.struts2.dispatcher.mapper.ActionMapper;
 import org.apache.struts2.StrutsException;
+import org.apache.struts2.RequestUtils;
 
 import javax.servlet.ServletException;
 import javax.servlet.ServletContext;
@@ -38,6 +39,8 @@
 
 import java.io.IOException;
 import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Pattern;
 
 /**
  * Contains preparation operations for a request before execution
@@ -179,4 +182,48 @@
             }
         }
     }
+
+    /**
+     * Check whether the request matches a list of exclude patterns.
+     *
+     * @param request          The request to check patterns against
+     * @param excludedPatterns list of patterns for exclusion
+     *
+     * @return <tt>true</tt> if the request URI matches one of the given 
patterns
+     */
+    public boolean isUrlExcluded( HttpServletRequest request, List<Pattern> 
excludedPatterns ) {
+        if (excludedPatterns != null) {
+            String uri = getUri(request);
+            for ( Pattern pattern : excludedPatterns ) {
+                if (pattern.matcher(uri).matches()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Gets the uri from the request
+     *
+     * @param request The request
+     *
+     * @return The uri
+     */
+    private String getUri( HttpServletRequest request ) {
+        // handle http dispatcher includes.
+        String uri = (String) 
request.getAttribute("javax.servlet.include.servlet_path");
+        if (uri != null) {
+            return uri;
+        }
+
+        uri = RequestUtils.getServletPath(request);
+        if (uri != null && !"".equals(uri)) {
+            return uri;
+        }
+
+        uri = request.getRequestURI();
+        return uri.substring(request.getContextPath().length());
+    }
+
 }

Modified: 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsExecuteFilter.java
URL: 
http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsExecuteFilter.java?rev=768529&r1=768528&r2=768529&view=diff
==============================================================================
--- 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsExecuteFilter.java
 (original)
+++ 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsExecuteFilter.java
 Sat Apr 25 13:49:50 2009
@@ -63,8 +63,15 @@
         HttpServletRequest request = (HttpServletRequest) req;
         HttpServletResponse response = (HttpServletResponse) res;
 
+               if (excludeUrl(request)) {
+                       chain.doFilter(request, response);
+                       return;
+               }
+
         // This is necessary since we need the dispatcher instance, which was 
created by the prepare filter
-        lazyInit();
+               if (execute == null) {
+                       lazyInit();
+               }
 
         ActionMapping mapping = prepare.findActionMapping(request, response);
         if (mapping == null) {
@@ -77,9 +84,13 @@
         }
     }
 
+       private boolean excludeUrl(HttpServletRequest request) {
+               return 
request.getAttribute(StrutsPrepareFilter.REQUEST_EXCLUDED_FROM_ACTION_MAPPING) 
!= null;
+       }
+
     public void destroy() {
         prepare = null;
         execute = null;
         filterConfig = null;
     }
-}
\ No newline at end of file
+}

Modified: 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareAndExecuteFilter.java
URL: 
http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareAndExecuteFilter.java?rev=768529&r1=768528&r2=768529&view=diff
==============================================================================
--- 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareAndExecuteFilter.java
 (original)
+++ 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareAndExecuteFilter.java
 Sat Apr 25 13:49:50 2009
@@ -22,15 +22,17 @@
 
 import org.apache.struts2.StrutsStatics;
 import org.apache.struts2.dispatcher.Dispatcher;
-import org.apache.struts2.dispatcher.ng.PrepareOperations;
+import org.apache.struts2.dispatcher.mapper.ActionMapping;
 import org.apache.struts2.dispatcher.ng.ExecuteOperations;
 import org.apache.struts2.dispatcher.ng.InitOperations;
-import org.apache.struts2.dispatcher.mapper.ActionMapping;
+import org.apache.struts2.dispatcher.ng.PrepareOperations;
 
 import javax.servlet.*;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.util.List;
+import java.util.regex.Pattern;
 
 /**
  * Handles both the preparation and execution phases of the Struts dispatching 
process.  This filter is better to use
@@ -39,6 +41,7 @@
 public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter {
     private PrepareOperations prepare;
     private ExecuteOperations execute;
+       protected List<Pattern> excludedPatterns = null;
 
     public void init(FilterConfig filterConfig) throws ServletException {
         InitOperations init = new InitOperations();
@@ -50,6 +53,7 @@
 
             prepare = new PrepareOperations(filterConfig.getServletContext(), 
dispatcher);
             execute = new ExecuteOperations(filterConfig.getServletContext(), 
dispatcher);
+                       this.excludedPatterns = 
init.buildExcludedPatternsList(dispatcher);
         } finally {
             init.cleanup();
         }
@@ -66,15 +70,19 @@
             prepare.createActionContext(request, response);
             prepare.assignDispatcherToThread();
             request = prepare.wrapRequest(request);
-            ActionMapping mapping = prepare.findActionMapping(request, 
response, true);
-            if (mapping == null) {
-                boolean handled = 
execute.executeStaticResourceRequest(request, response);
-                if (!handled) {
-                    chain.doFilter(request, response);
-                }
-            } else {
-                execute.executeAction(request, response, mapping);
-            }
+                       if ( excludedPatterns != null && 
prepare.isUrlExcluded(request, excludedPatterns)) {
+                               chain.doFilter(request, response);
+                       } else {
+                               ActionMapping mapping = 
prepare.findActionMapping(request, response, true);
+                               if (mapping == null) {
+                                       boolean handled = 
execute.executeStaticResourceRequest(request, response);
+                                       if (!handled) {
+                                               chain.doFilter(request, 
response);
+                                       }
+                               } else {
+                                       execute.executeAction(request, 
response, mapping);
+                               }
+                       }
         } finally {
             prepare.cleanupRequest(request);
         }

Modified: 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareFilter.java
URL: 
http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareFilter.java?rev=768529&r1=768528&r2=768529&view=diff
==============================================================================
--- 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareFilter.java
 (original)
+++ 
struts/struts2/trunk/core/src/main/java/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareFilter.java
 Sat Apr 25 13:49:50 2009
@@ -22,21 +22,27 @@
 
 import org.apache.struts2.StrutsStatics;
 import org.apache.struts2.dispatcher.Dispatcher;
-import org.apache.struts2.dispatcher.ng.PrepareOperations;
 import org.apache.struts2.dispatcher.ng.InitOperations;
+import org.apache.struts2.dispatcher.ng.PrepareOperations;
 
 import javax.servlet.*;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.util.List;
+import java.util.regex.Pattern;
 
 /**
  * Prepares the request for execution by a later {...@link 
org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter} filter instance.
  */
 public class StrutsPrepareFilter implements StrutsStatics, Filter {
+
+       protected static final String REQUEST_EXCLUDED_FROM_ACTION_MAPPING = 
StrutsPrepareFilter.class.getName() + ".REQUEST_EXCLUDED_FROM_ACTION_MAPPING";
+
     private PrepareOperations prepare;
+       private List<Pattern> excludedPatterns = null;
 
-    public void init(FilterConfig filterConfig) throws ServletException {
+       public void init(FilterConfig filterConfig) throws ServletException {
         InitOperations init = new InitOperations();
         try {
             FilterHostConfig config = new FilterHostConfig(filterConfig);
@@ -44,6 +50,7 @@
             Dispatcher dispatcher = init.initDispatcher(config);
 
             prepare = new PrepareOperations(filterConfig.getServletContext(), 
dispatcher);
+                       this.excludedPatterns = 
init.buildExcludedPatternsList(dispatcher);
         } finally {
             init.cleanup();
         }
@@ -60,15 +67,18 @@
             prepare.createActionContext(request, response);
             prepare.assignDispatcherToThread();
             request = prepare.wrapRequest(request);
-            prepare.findActionMapping(request, response);
-
+                       if ( excludedPatterns != null && 
prepare.isUrlExcluded(request, excludedPatterns)) {
+                               
request.setAttribute(REQUEST_EXCLUDED_FROM_ACTION_MAPPING, new Object());
+                       } else {
+                               prepare.findActionMapping(request, response);
+                       }
             chain.doFilter(request, response);
         } finally {
             prepare.cleanupRequest(request);
         }
     }
 
-    public void destroy() {
+       public void destroy() {
         prepare.cleanupDispatcher();
     }
 }
\ No newline at end of file

Modified: 
struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ng/StrutsPrepareAndExecuteFilterIntegrationTest.java
URL: 
http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ng/StrutsPrepareAndExecuteFilterIntegrationTest.java?rev=768529&r1=768528&r2=768529&view=diff
==============================================================================
--- 
struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ng/StrutsPrepareAndExecuteFilterIntegrationTest.java
 (original)
+++ 
struts/struts2/trunk/core/src/test/java/org/apache/struts2/dispatcher/ng/StrutsPrepareAndExecuteFilterIntegrationTest.java
 Sat Apr 25 13:49:50 2009
@@ -32,7 +32,10 @@
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
+import javax.servlet.FilterConfig;
 import java.io.IOException;
+import java.util.regex.Pattern;
+import java.util.ArrayList;
 
 /**
  * Integration tests for the filter
@@ -113,6 +116,32 @@
         assertTrue((Boolean) request.getAttribute("__invoked"));
     }
 
+    public void testUriPatternExclusion() throws ServletException, IOException 
{
+        MockHttpServletRequest request = new MockHttpServletRequest();
+        MockHttpServletResponse response = new MockHttpServletResponse();
+        MockFilterConfig filterConfig = new MockFilterConfig();
+        MockFilterChain filterChain = new MockFilterChain() {
+            @Override
+            public void doFilter(ServletRequest req, ServletResponse res) {
+                req.setAttribute("i_was", "invoked");
+            }
+        };
+
+        request.setRequestURI("/hello.action");
+        StrutsPrepareAndExecuteFilter filter = new 
StrutsPrepareAndExecuteFilter() {
+            @Override
+            public void init( FilterConfig filterConfig ) throws 
ServletException {
+                super.init(filterConfig);
+                excludedPatterns = new ArrayList<Pattern>();
+                excludedPatterns.add(Pattern.compile(".*hello.*"));
+            }
+        };
+        filter.init(filterConfig);
+        filter.doFilter(request, response, filterChain);
+        assertEquals(200, response.getStatus());
+        assertEquals("invoked", request.getAttribute("i_was"));
+    }
+
     public void testStaticFallthrough() throws ServletException, IOException {
         MockHttpServletRequest request = new MockHttpServletRequest();
         MockHttpServletResponse response = new MockHttpServletResponse();


Reply via email to