craigmcc    2002/07/03 17:05:48

  Modified:    conf/share struts-config_1_1.dtd
               src/share/org/apache/struts/config ControllerConfig.java
                        ForwardConfig.java
               src/share/org/apache/struts/util RequestUtils.java
               src/test/org/apache/struts/util TestRequestUtils.java
  Log:
  Support pluggable patterns for mapping the path of an ActionForward (if it
  is not marked context relative), or the path specified by the "page"
  attribute of many tags, so that you can gracefully deal with things like
  migrating your JSP pages under /WEB-INF.
  
  The syntax for the "forwardPattern" and "pagePattern" patterns is simple:
    $C is replaced by the context path of this webapp
    $A is replaced by the prefix for this subapp
    $P is replaced by the path of the forward (for forwardPattern)
       or the specified page value (for pagePattern)
    $$ is replaced by a literal $
    all other characters are passed through unchanged.
  
  The default pattern in each case is "$C$A$P", which is consistent with the
  previous behavior (and optimized for performance in the code).  To put your
  pages under "/WEB-INF/pages" instead of the context root, specify a pattern
  like "$C/WEB-INF/pages$A$P" instead.
  
  Added unit tests to validate the new behavior (including consistent
  behavior of the previous defaults).
  
  FIXME - Update ImageTag and ImgTag to use RequestUtils.computeURL() so that
  they will pick up changes like this automatically.
  
  Revision  Changes    Path
  1.20      +39 -2     jakarta-struts/conf/share/struts-config_1_1.dtd
  
  Index: struts-config_1_1.dtd
  ===================================================================
  RCS file: /home/cvs/jakarta-struts/conf/share/struts-config_1_1.dtd,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- struts-config_1_1.dtd     30 Jun 2002 04:37:32 -0000      1.19
  +++ struts-config_1_1.dtd     4 Jul 2002 00:05:47 -0000       1.20
  @@ -289,7 +289,12 @@
   
        path            The application-relative or context-relative path of
                        the mapped resource (determined by the selected value
  -                     for the "contextRelative" attribute).
  +                     for the "contextRelative" attribute).  If contextRelative
  +                     is false, this value is used in a calculation based on
  +                     the "forwardPattern" property of the controller parameters
  +                     for the current sub-application to calculate the
  +                     resulting value.  This value must begin with a slash
  +                     ("/") character.
   
        redirect        Set to "true" if sendRedirect() should be used to forward
                        to this resource, or "false" in order to use
  @@ -434,6 +439,22 @@
   
        debug           Debugging detail level for this application.  [0]
   
  +     forwardPattern  Replacement pattern defining how the "path" attribute of
  +                     a "forward" element is mapped to a server-relative URL
  +                     when it starts with a slash (and when the contextRelative
  +                     property is false).  This value may consist of any
  +                     combination of the following:
  +                     - "$C" - Replaced by the context path of this webapp
  +                     - "$A" - Replaced by the app prefix of this subapp
  +                     - "$P" - Replaced by the "path" attribute of the
  +                              selected "forward" element
  +                     - "$$" - Causes a literal dollar sign to be rendered
  +                     - "$x" - (Where "x" is any character not defined above)
  +                              Silently swallowed, reserved for future use
  +                     If not specified, the default forwardPattern is
  +                     "$C$A$P", which is consistent with previous hard coded
  +                     behavior of forwards.
  +
        locale          Set to true if you want a Locale object stored in the
                        user's session if not already present.  [true]
   
  @@ -450,6 +471,20 @@
                        HTTP headers for defeating caching to every response.
                        [false]
   
  +     pagePattern     Replacement pattern defining how the "page" attribute of
  +                     custom tags that use it is mapped to a server-relative URL
  +                     of the corresponding resource.  This value may consist of
  +                     any combination of the following:
  +                     - "$C" - Replaced by the context path of this webapp
  +                     - "$A" - Replaced by the app prefix of this subapp
  +                     - "$P" - Replaced by the value of the "page" attribute
  +                     - "$$" - Causes a literal dollar sign to be rendered
  +                     - "$x" - (Where "x" is any character not defined above)
  +                              Silently swallowed, reserved for future use
  +                     If not specified, the default forwardPattern is
  +                     "$C$A$P", which is consistent with previous hard coded
  +                     behavior of URL evaluation for "page" attributes.
  +
        processorClass  The fully qualified Java class name of the
                        RequestProcessor class to be used.
                        [org.apache.struts.action.RequestProcessor]
  @@ -463,10 +498,12 @@
   <!ATTLIST controller     className      %ClassName;     #IMPLIED>
   <!ATTLIST controller     contentType    CDATA           #IMPLIED>
   <!ATTLIST controller     debug          %Integer;       #IMPLIED>  
  +<!ATTLIST controller     forwardPattern CDATA           #IMPLIED>
   <!ATTLIST controller     locale         %Boolean;       #IMPLIED>
   <!ATTLIST controller     maxFileSize    CDATA           #IMPLIED>
   <!ATTLIST controller     multipartClass %ClassName;     #IMPLIED>
   <!ATTLIST controller     nocache        %Boolean;       #IMPLIED>
  +<!ATTLIST controller     pagePattern    CDATA           #IMPLIED>
   <!ATTLIST controller     processorClass %ClassName;     #IMPLIED>
   <!ATTLIST controller     tempDir        CDATA           #IMPLIED>
   
  
  
  
  1.5       +73 -4     
jakarta-struts/src/share/org/apache/struts/config/ControllerConfig.java
  
  Index: ControllerConfig.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-struts/src/share/org/apache/struts/config/ControllerConfig.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ControllerConfig.java     23 Feb 2002 23:53:29 -0000      1.4
  +++ ControllerConfig.java     4 Jul 2002 00:05:48 -0000       1.5
  @@ -143,6 +143,40 @@
   
   
       /**
  +     * <p>The replacement pattern used to determine a server-relative URL
  +     * from a {@link ForwardConfig} element.  The pattern may consist of any
  +     * combination of the following markers and characters:</p>
  +     * <ul>
  +     * <li><code><strong>$C</strong></code> - Replaced by the context path
  +     *     of the current web-application.</li>
  +     * <li><code><strong>$A</strong></code> - Replaced by the application
  +     *     prefix for the current subapplication.</li>
  +     * <li><code><strong>$P</strong></code> - Replaced by the <code>path</code>
  +     *     property of a {@link ForwardConfig} instance.</li>
  +     * <li><code><strong>$$</strong></code> - Renders a literal dollar sign
  +     *     ("$") character in the resulting URL.</li>
  +     * <li>A dollar sign followed by any other character is reserved for
  +     *     future use, and both characters are silently swallowed.</li>
  +     * <li>All other characters in the pattern are passed through unchanged.
  +     *     </li>
  +     * </ul>
  +     *
  +     * <p>If this property is set to <code>null</code>, a default pattern of
  +     * <code>$C$A$P</code> is utilized, which is backwards compatible with
  +     * the hard coded functionality in prior versions.</p>
  +     */
  +    protected String forwardPattern = null;
  +
  +    public String getForwardPattern() {
  +        return (this.forwardPattern);
  +    }
  +
  +    public void setForwardPattern(String forwardPattern) {
  +        this.forwardPattern = forwardPattern;
  +    }
  +
  +
  +    /**
        * Should we store a Locale object in the user's session if needed?
        */
       protected boolean locale = false;
  @@ -209,6 +243,41 @@
               throw new IllegalStateException("Configuration is frozen");
           }
           this.nocache = nocache;
  +    }
  +
  +
  +    /**
  +     * <p>The replacement pattern used to determine a server-relative URL
  +     * from the <code>page</code> attribute of Struts tags and configuration
  +     * properties.  The pattern may consist of any combination of the
  +     * following markers and characters:</p>
  +     * <ul>
  +     * <li><code><strong>$C</strong></code> - Replaced by the context path
  +     *     of the current web-application.</li>
  +     * <li><code><strong>$A</strong></code> - Replaced by the application
  +     *     prefix for the current subapplication.</li>
  +     * <li><code><strong>$P</strong></code> - Replaced by the <code>page</code>
  +     *     attribute value being evaluated.</li>
  +     * <li><code><strong>$$</strong></code> - Renders a literal dollar sign
  +     *     ("$") character in the resulting URL.</li>
  +     * <li>A dollar sign followed by any other character is reserved for
  +     *     future use, and both characters are silently swallowed.</li>
  +     * <li>All other characters in the pattern are passed through unchanged.
  +     *     </li>
  +     * </ul>
  +     *
  +     * <p>If this property is set to <code>null</code>, a default pattern of
  +     * <code>$C$A$P</code> is utilized, which is backwards compatible with
  +     * the hard coded functionality in prior versions.</p>
  +     */
  +    protected String pagePattern = null;
  +
  +    public String getPagePattern() {
  +        return (this.pagePattern);
  +    }
  +
  +    public void setPagePattern(String pagePattern) {
  +        this.pagePattern = pagePattern;
       }
   
   
  
  
  
  1.5       +21 -7     
jakarta-struts/src/share/org/apache/struts/config/ForwardConfig.java
  
  Index: ForwardConfig.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-struts/src/share/org/apache/struts/config/ForwardConfig.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- ForwardConfig.java        2 Jul 2002 01:52:15 -0000       1.4
  +++ ForwardConfig.java        4 Jul 2002 00:05:48 -0000       1.5
  @@ -159,9 +159,23 @@
   
   
       /**
  -     * The application-relative (if contextRelative is <code>false</code>) or
  -     * context-relative (if contextRelative is <code>true</code>) path,
  -     * starting with a "/", of the resource that is mapped by this forward.
  +     * <p>The URL to which this <code>ForwardConfig</code> entry points,
  +     * which must start with a slash ("/") character.  It is
  +     * interpreted according to the following rules:</p>
  +     * <li>If <code>contextRelative</code> property is <code>true</code>, the
  +     *     path is considered to be context-relative within the current web
  +     *     application (even if we are in a sub-application).  It will be
  +     *     prefixed by the context path to create a server-relative URL.</li>
  +     * <li>If the <code>contextRelative</code> property is false, the path is
  +     *     considered to be the application-relative portion of the URL.
  +     *     It will be used as the replacement for the <code>$F</code>
  +     *     marker in the <code>forwardPattern</code> property defined on the
  +     *     {@link ControllerConfig} element for our current sub-application.
  +     *     For the default <code>forwardPattern</code> value of
  +     *     <code>$C$A$P</code>, the resulting server-relative URL will be
  +     *     the concatenation of the context path, the sub-application prefix,
  +     *     and the <code>path</code> from this <code>ForwardConfig</code>.</li>
  +     * </ul>
        */
       protected String path = null;
   
  
  
  
  1.42      +133 -20   
jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java
  
  Index: RequestUtils.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-struts/src/share/org/apache/struts/util/RequestUtils.java,v
  retrieving revision 1.41
  retrieving revision 1.42
  diff -u -r1.41 -r1.42
  --- RequestUtils.java 2 Jul 2002 01:51:10 -0000       1.41
  +++ RequestUtils.java 4 Jul 2002 00:05:48 -0000       1.42
  @@ -100,6 +100,7 @@
   import org.apache.struts.action.RequestProcessor;
   import org.apache.struts.config.ApplicationConfig;
   import org.apache.struts.config.FormBeanConfig;
  +import org.apache.struts.config.ForwardConfig;
   import org.apache.struts.taglib.html.Constants;
   import org.apache.struts.upload.FormFile;
   import org.apache.struts.upload.MultipartRequestHandler;
  @@ -393,6 +394,8 @@
               config = (ApplicationConfig)
                   pageContext.getServletContext().getAttribute
                   (Action.APPLICATION_KEY);
  +            pageContext.getRequest().setAttribute(Action.APPLICATION_KEY,
  +                                                  config);
           }
   
           // Calculate the appropriate URL
  @@ -400,30 +403,19 @@
           HttpServletRequest request =
               (HttpServletRequest) pageContext.getRequest();
           if (forward != null) {
  -            ActionForward af =
  -                (ActionForward) config.findForwardConfig(forward);
  -            if (af == null) {
  +            ForwardConfig fc = config.findForwardConfig(forward);
  +            if (fc == null) {
                   throw new MalformedURLException
                       (messages.getMessage("computeURL.forward", forward));
               }
  -            if (af.getRedirect()) {
  +            if (fc.getRedirect()) {
                   redirect = true;
               }
  -            if (af.getPath().startsWith("/")) {
  -                url.append(request.getContextPath());
  -                if ((config != null) && !af.getContextRelative()) {
  -                    url.append(config.getPrefix());
  -                }
  -            }
  -            url.append(af.getPath());
  +            url.append(forwardURL(request, fc));
           } else if (href != null) {
               url.append(href);
           } else /* if (page != null) */ {
  -            url.append(request.getContextPath());
  -            if (config != null) {
  -                url.append(config.getPrefix());
  -            }
  -            url.append(page);
  +            url.append(pageURL(request, page));
           }
   
           // Add anchor if requested (replacing any existing anchor)
  @@ -1141,6 +1133,127 @@
               sb.append(ref);
               return (sb.toString());
           }
  +
  +    }
  +
  +
  +    /**
  +     * Return the server-relative URL that corresponds to the specified
  +     * {@link ForwardConfig}, relative to the sub-application associated
  +     * with the current subapp's {@link ApplicationConfig}.
  +     *
  +     * @param request The servlet request we are processing
  +     * @param forward ForwardConfig to be evaluated
  +     */
  +    public static String forwardURL(HttpServletRequest request,
  +                                    ForwardConfig forward) {
  +
  +        // Handle a ForwardConfig marked as context relative
  +        StringBuffer sb = new StringBuffer();
  +        if (forward.getContextRelative()) {
  +            sb.append(request.getContextPath());
  +            sb.append(forward.getPath());
  +            return (sb.toString());
  +        }
  +
  +        // Calculate a subapp relative path for this ForwardConfig
  +        ApplicationConfig appConfig = (ApplicationConfig)
  +            request.getAttribute(Action.APPLICATION_KEY);
  +        String forwardPattern =
  +            appConfig.getControllerConfig().getForwardPattern();
  +        if (forwardPattern == null) {
  +            // Performance optimization for previous default behavior
  +            sb.append(request.getContextPath());
  +            sb.append(appConfig.getPrefix());
  +            sb.append(forward.getPath());
  +        } else {
  +            boolean dollar = false;
  +            for (int i = 0; i < forwardPattern.length(); i++) {
  +                char ch = forwardPattern.charAt(i);
  +                if (dollar) {
  +                    switch (ch) {
  +                    case 'C':
  +                        sb.append(request.getContextPath());
  +                        break;
  +                    case 'A':
  +                        sb.append(appConfig.getPrefix());
  +                        break;
  +                    case 'P':
  +                        sb.append(forward.getPath());
  +                        break;
  +                    case '$':
  +                        sb.append('$');
  +                        break;
  +                    default:
  +                        ; // Silently swallow
  +                    }
  +                    dollar = false;
  +                    continue;
  +                } else if (ch == '$') {
  +                    dollar = true;
  +                } else {
  +                    sb.append(ch);
  +                }
  +            }
  +        }
  +        return (sb.toString());
  +
  +    }
  +
  +
  +    /**
  +     * Return the server-relative URL that corresponds to the specified
  +     * <code>page</code> attribute value, calculated based on the
  +     * <code>pagePattern</code> property of the current subapp's
  +     * {@link ApplicationConfig}.
  +     *
  +     * @param request The servlet request we are processing
  +     * @param page The application-relative URL to be substituted in
  +     *  to the <code>pagePattern</code> pattern for the current subapp
  +     */
  +    public static String pageURL(HttpServletRequest request,
  +                                 String page) {
  +
  +        StringBuffer sb = new StringBuffer();
  +        ApplicationConfig appConfig = (ApplicationConfig)
  +            request.getAttribute(Action.APPLICATION_KEY);
  +        String pagePattern =
  +            appConfig.getControllerConfig().getPagePattern();
  +        if (pagePattern == null) {
  +            sb.append(request.getContextPath());
  +            sb.append(appConfig.getPrefix());
  +            sb.append(page);
  +        } else {
  +            boolean dollar = false;
  +            for (int i = 0; i < pagePattern.length(); i++) {
  +                char ch = pagePattern.charAt(i);
  +                if (dollar) {
  +                    switch (ch) {
  +                    case 'C':
  +                        sb.append(request.getContextPath());
  +                        break;
  +                    case 'A':
  +                        sb.append(appConfig.getPrefix());
  +                        break;
  +                    case 'P':
  +                        sb.append(page);
  +                        break;
  +                    case '$':
  +                        sb.append('$');
  +                        break;
  +                    default:
  +                        ; // Silently swallow
  +                    }
  +                    dollar = false;
  +                    continue;
  +                } else if (ch == '$') {
  +                    dollar = true;
  +                } else {
  +                    sb.append(ch);
  +                }
  +            }
  +        }
  +        return (sb.toString());
   
       }
   
  
  
  
  1.3       +101 -5    
jakarta-struts/src/test/org/apache/struts/util/TestRequestUtils.java
  
  Index: TestRequestUtils.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-struts/src/test/org/apache/struts/util/TestRequestUtils.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- TestRequestUtils.java     2 Jul 2002 04:23:14 -0000       1.2
  +++ TestRequestUtils.java     4 Jul 2002 00:05:48 -0000       1.3
  @@ -457,6 +457,7 @@
       // Default subapp -- Href only
       public void testComputeURL1b() {
   
  +        request.setPathElements("/myapp", "/action.do", null, null);
           String url = null;
           try {
               url = RequestUtils.computeURL
  @@ -495,6 +496,52 @@
       }
   
   
  +    // Default subapp -- Forward with pattern
  +    public void testComputeURL1d() {
  +
  +        appConfig.getControllerConfig().setForwardPattern
  +            ("$C/WEB-INF/pages$A$P");
  +        request.setPathElements("/myapp", "/action.do", null, null);
  +        String url = null;
  +        try {
  +            url = RequestUtils.computeURL
  +                (page, "foo",
  +                 null, null,
  +                 null, null, false);
  +        } catch (MalformedURLException e) {
  +            fail("MalformedURLException: " + e);
  +        }
  +        assertNotNull("url present", url);
  +        assertEquals("url value",
  +                     "/myapp/WEB-INF/pages/bar.jsp",
  +                     url);
  +
  +    }
  +
  +
  +    // Default subapp -- Page with pattern
  +    public void testComputeURL1e() {
  +
  +        appConfig.getControllerConfig().setPagePattern
  +            ("$C/WEB-INF/pages$A$P");
  +        request.setPathElements("/myapp", "/action.do", null, null);
  +        String url = null;
  +        try {
  +            url = RequestUtils.computeURL
  +                (page, null,
  +                 null, "/bar",
  +                 null, null, false);
  +        } catch (MalformedURLException e) {
  +            fail("MalformedURLException: " + e);
  +        }
  +        assertNotNull("url present", url);
  +        assertEquals("url value",
  +                     "/myapp/WEB-INF/pages/bar",
  +                     url);
  +
  +    }
  +
  +
       // Second subapp -- Forward only
       public void testComputeURL2a() {
   
  @@ -521,6 +568,7 @@
       public void testComputeURL2b() {
   
           request.setAttribute(Action.APPLICATION_KEY, appConfig2);
  +        request.setPathElements("/myapp", "/2/action.do", null, null);
           String url = null;
           try {
               url = RequestUtils.computeURL
  @@ -542,7 +590,7 @@
       public void testComputeURL2c() {
   
           request.setAttribute(Action.APPLICATION_KEY, appConfig2);
  -        request.setPathElements("/myapp", "/action.do", null, null);
  +        request.setPathElements("/myapp", "/2/action.do", null, null);
           String url = null;
           try {
               url = RequestUtils.computeURL
  @@ -555,6 +603,54 @@
           assertNotNull("url present", url);
           assertEquals("url value",
                        "/myapp/2/bar",
  +                     url);
  +
  +    }
  +
  +
  +    // Default subapp -- Forward with pattern
  +    public void testComputeURL2d() {
  +
  +        request.setAttribute(Action.APPLICATION_KEY, appConfig2);
  +        appConfig2.getControllerConfig().setForwardPattern
  +            ("$C/WEB-INF/pages$A$P");
  +        request.setPathElements("/myapp", "/2/action.do", null, null);
  +        String url = null;
  +        try {
  +            url = RequestUtils.computeURL
  +                (page, "foo",
  +                 null, null,
  +                 null, null, false);
  +        } catch (MalformedURLException e) {
  +            fail("MalformedURLException: " + e);
  +        }
  +        assertNotNull("url present", url);
  +        assertEquals("url value",
  +                     "/myapp/WEB-INF/pages/2/baz.jsp",
  +                     url);
  +
  +    }
  +
  +
  +    // Second subapp -- Page with pattern
  +    public void testComputeURL2e() {
  +
  +        appConfig2.getControllerConfig().setPagePattern
  +            ("$C/WEB-INF/pages$A$P");
  +        request.setAttribute(Action.APPLICATION_KEY, appConfig2);
  +        request.setPathElements("/myapp", "/2/action.do", null, null);
  +        String url = null;
  +        try {
  +            url = RequestUtils.computeURL
  +                (page, null,
  +                 null, "/bar",
  +                 null, null, false);
  +        } catch (MalformedURLException e) {
  +            fail("MalformedURLException: " + e);
  +        }
  +        assertNotNull("url present", url);
  +        assertEquals("url value",
  +                     "/myapp/WEB-INF/pages/2/bar",
                        url);
   
       }
  
  
  

--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to