You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

Tapestry URL Rewriting Support

Since 5.1.0.1, Tapestry has basic support for URL rewriting. Incoming requests and links generated by Tapestry can be rewritten using exactly the same API. It is based on a chain of URLRewriterRule interfaces. These rules are executed before all other Tapestry request handling, so it does not even know that the received request is not the original one.

Each URL rewriter rule, in its Request process, can choose between returning another Request, effectively rewriting it, or returning the received request unchanged, meaning that this rule does not apply to that request.

To create facilitate Request creation, Tapestry provides the SimpleRequestWrapper class. It wraps an Request, delegating all methods except getPath() and getServerName(). More request wrappers may be added in the future on demand.

Configuration

Tapestry's URL rewriting support is configured by Tapestry-Ioc through contribution of URLRewriterRule}}s to the {{URLRewriter service. The following example is part of the Tapestry's tests.

Simple example of rule chaining

This example just rewrites all incoming requests to /struts to /tapestry. In your AppModule or any other Tapestry-IoC module class:


public static void contributeURLRewriter(OrderedConfiguration<URLRewriterRule> configuration)
{
    
    URLRewriterRule rule = new URLRewriterRule() 
    {

        public Request process(Request request, URLRewriteContext context)
        {
            final String path = request.getPath();
            if (path.equals("/struts"))
            {
                request = new SimpleRequestWrapper(request, "/tapestry");
            }
            
            return request;
            
        }

        public RewriteRuleApplicability applicability()
        {
            return RewriteRuleApplicability.INBOUND;
        }
        
    };
    
    configuration.add("myrule", rule);
}

Example of rule chaining

In your AppModule or any other Tapestry-IoC module class.


public static void contributeURLRewriter(OrderedConfiguration<URLRewriterRule> configuration)
{
    
    URLRewriterRule rule1 = new URLRewriterRule()
    {

        public Request process(Request request, URLRewriteContext context)
        {
            final String path = request.getPath();
            if (path.equals("/struts")) 
            {
                request = new SimpleRequestWrapper(request, "/jsf");
            }
            
            return request;
            
        }

        public RewriteRuleApplicability applicability()
        {
            return RewriteRuleApplicability.INBOUND;
        } 
        
    };
    
    URLRewriterRule rule2 = new URLRewriterRule()
    {

        public Request process(Request request, URLRewriteContext context)
        {
            final String path = request.getPath();
            if (path.equals("/jsf")) 
            {
                request = new SimpleRequestWrapper(request, "/tapestry");
            }
            return request;
            
        }
        
        public RewriteRuleApplicability applicability()
        {
            return RewriteRuleApplicability.INBOUND;
        }

    };
    
    URLRewriterRule rule3 = new URLRewriterRule()
    {

        public Request process(Request request, URLRewriteContext context)
        {
            String path = request.getPath();
            if (path.equals("/tapestry")) 
            {
                path = "/urlrewritesuccess";
                request = new SimpleRequestWrapper(request, path);
            }
            return request;
            
        }
        
        public RewriteRuleApplicability applicability()
        {
            return RewriteRuleApplicability.INBOUND;
        }

    };
    
    URLRewriterRule rule4 = new URLRewriterRule()
    {

        public Request process(Request request, URLRewriteContext context)
        {
            String serverName = request.getServerName();
            String path = request.getPath();
            final String pathToRewrite = "/urlrewritesuccess/login";
            if (serverName.equals("localhost") && path.equalsIgnoreCase(pathToRewrite)) 
            {
                request = new SimpleRequestWrapper(request, "http://login.domain.com", "/");
            }
            return request;
            
        }

        public RewriteRuleApplicability applicability()
        {
            return RewriteRuleApplicability.OUTBOUND;
        }


    };    
    
    configuration.add("rule1", rule1);
    configuration.add("rule2", rule2, "after:rule1");
    configuration.add("rule3", rule3, "after:rule2");
    configuration.add("rule4", rule4);
    
}

This examples shows the URL rewriting chaining: the first rule rewrites requests to /struts and rewrites them to /jsf and leaves requests to other URLs unchanged. The second rewrites /jsf to /tapestry and the third rewrites /tapestry to /urlrewritesuccess.

The result is that any request to /struts end up being handled by the same class that handles /urlrewritesuccess, while the browser, the user and Tapestry still sees /struts.

Note that this applies to rewriting links generated by Tapestry too: a PageLink to the urlrewritesuccess page with an activation context of login (path /urlrewritesuccess/login) will generate an a tag pointing to http://login.domain.com.

The URLRewriteContext (added in 5.1.0.4) provides additional information for rewriting, particularly in the context of rewriting generated link urls. In the following example, we'll reconfigure the url used to render pages. Whereas the previous examples used separate rules for handling inbound and outbound rewriting, this demonstration will utilize a single rule for both scenarios. To simplify the example, we will assume that every page is named "XXXPage" (UserPage, TransactionPage, IndexPage, etc.). This naming convention also means that we don't have to worry about tapestry's auto-stripping of "index" from urls, because our page would be IndexPage, rather than Index.


public static void contributeURLRewriter(OrderedConfiguration<URLRewriterRule> configuration)
{
    URLRewriterRule rule = new URLRewriterRule() 
    {
        public Request process(Request request, URLRewriteContext context)
        {
            if (context.isIncoming())
            {
                //these look like component event requests, which we didn't rewrite, so ignore.
                if (request.getPath().contains(".") || request.getPath().contains(":")) 
                {
                    return request;
                }
                String pageName = request.getPath().substring(1,request.getPath().indexOf('/',1));
                return new SimpleRequestWrapper(request, request.getPath().replaceAll(pageName,pageName + "page"));
            }
            else
            {
               //if this is a component event, getPageParameters() will return null.
               if (context.getPageParameters() != null) 
               {
                    String path = request.getPath();
                    String pageName = context.getPageParameters().getLogicalPageName().toLowerCase();
                    String newPageName = pageName.replaceAll("page$","");
                    return new SimpleRequestWrapper(request,path.replaceAll(pageName,newPageName));
               }
            }
            return request;
        }

        public RewriteRuleApplicability applicability()
        {
            return RewriteRuleApplicability.BOTH;
        }
    };

    configuration.add("rule1",rule);

}

In the first part of process, context.isIncoming() determines if the call to process occured due to an inbound request. If so, the rule reverses the mapping done in the second portion of the method, so tapestry sees the original request.

The second half of process rewrites only page links by retrieving the logical page name and replacing its occurence in the url with the shortened form of the link. This code segment demonstrates how the additional information provided by URLRewriteContext can be used to rewrite urls in a generalized manner.

Note that getPageParameters() will only return non-null when process is called due to page link creation, and getComponentEventParameters() will only return non-null when process is called as a result of creating component event links.

  • No labels