Rewrite Examples

Frequently the best way to learn how to use a technology is to see examples of how it has been used in similar situations. Here are some examples of how to use Rewrite‘s core Servlet functionality in common scenarios. For the purpose of brevity, extraneous code has been omitted.

Before you get started with Rewrite, you may wish to read the installation guide or configuration manual, including instructions for using Rewrite annotations, or migrating from PrettyFaces 3.x.

The following examples will show a few ways to get started using Rewrite; however, in reality, rewrite is a flexible tool, and be used for any purpose, not limited to those listed below.

Join an inbound URL to a server-side resource:

Typically the most basic task – masking the URL of an internal resource with another URL of your choice.
Exhibit 0
public class ExampleConfigurationProvider extends HttpConfigurationProvider
{

   @Override
   public Configuration getConfiguration(final ServletContext context)
   {
      return ConfigurationBuilder.begin()

          // A basic join
          .addRule(Join.path("/").to("/pages/home.xhtml"))

          // Using parameters to return physical resources
          .addRule(Join.path("/{param}").to("/pages/{param}.html"))

          // Using parameterization (the value of 'p' is converted to a request parameter)
          .addRule(Join.path("/project/{p}").to("/pages/project/create.xhtml"))

          // Redirect requests to the server-side resource to the correct location
          .addRule(Join.path("/signup").to("/pages/signup.xhtml").withInboundCorrection())

          // Perform additional operations on rule execution
          .addRule(Join.path("/404").to("/pages/404.xhtml").perform(Response.setCode(404)));

   }

}

Activate a Configuration Based on Dev/Test/Production Environment Detection

A frequent concern, is the ability to run configuration in a specific deployment environment. In this case, it is sometimes necessary to distinguish between test and production servers. Our recommendation for this is to use one of a few techniques. (This can be done in whichever manner fits your needs, but here are a few examples.)
Exhibit 1
public class EnvironmentDetectionConfigurationProvider extends HttpConfigurationProvider
{
   @Override
   public Configuration getConfiguration(ServletContext context)
   {
      return ConfigurationBuilder
               .begin()

               // Using File Markers
               .addRule().when(Filesystem.fileExists(new File("/root/env/server/production.marker")))
               .perform(Subset.evaluate(ConfigurationBuilder.begin()
                        // Your specific rules here
               )

               // Using URL domain detection
               .addRule().when(Domain.matches("{server}.domain.com"))
               .perform(Subset.evaluate(ConfigurationBuilder.begin()
                        .addRule(Join.path("/production-monitor").to("/views/monitor.jsp?servername={server}"))
                        // Your specific rules here (example using rule parameters)
                        .where("server").matches("prod1|prod2|prod3"))
               )

               // Using a custom condition (example shows using a "-P" jvm system property)
               .addRule()
               .when(new HttpCondition() {
                  @Override
                  public boolean evaluateHttp(HttpServletRewrite event, EvaluationContext context)
                  {
                     return Boolean.getBoolean("production.mode.enabled"); // Using a system property.
                  }
               })
               .perform(Subset.evaluate(ConfigurationBuilder.begin()
                        .addRule().when(JAASRoles.required("admin"))
                        .perform(Lifecycle.proceed()).otherwise(Forward.to("/login")))
                        // Your specific rules here
               );
   }
}

Create a dynamic logout URL without the need for a Servlet or page

Why write a full logout page, just to do what can be done with a single method call?
Exhibit 2
public class ExampleConfigurationProvider extends HttpConfigurationProvider
{
   @Override
   public Configuration getConfiguration(final ServletContext context)
   {
      return ConfigurationBuilder.begin()

          // Create a dynamic logout URL via EL
          .addRule()
          .when(Direction.isInbound().and(Path.matches("/logout")))
          .perform(Invoke.binding(El.retrievalMethod("#{session.invalidate}"))
                   .and(Redirect.temporary(context.getContextPath() + "/")))

          // Create a dynamic logout URL via direct service call
          .addRule()
          .when(Direction.isInbound().and(Path.matches("/logout")))
          .perform(new HttpOperation() {
             @Override
             public void performHttp(HttpServletRewrite event, EvaluationContext context)
             {
                event.getRequest().getSession().invalidate();
             }
          })
          .and(Redirect.temporary(context.getContextPath() + "/"));

   }
}

Show different resources when a user is logged in/logged out

Showing different content to users in different roles is a paramount task in any web application.
Exhibit 3
public class AuthenticationStatusInterceptor extends HttpConfigurationProvider
{
   @Inject
   @LoggedIn
   private Profile profile;

   @Override
   public Configuration getConfiguration(final ServletContext context)
   {
         Condition loggedIn = new Condition() {
                 @Override
                 public boolean evaluate(Rewrite event, EvaluationContext context) {
                    return profile.isLoggedIn();
                 }
              };

         /*
          * If the user is not logged in, show them the guest home page instead of the dashboard.
          */
         return ConfigurationBuilder.begin()
              .addRule(Join.path("/")
                      .to("/pages/loggedOffHome.xhtml"))
              .when(loggedIn)

              .addRule()
              .when(Direction.isInbound()
                      .and(Path.matches("/(signup|login)")
                      .andNot(loggedIn)))
              .perform(Redirect.temporary(context.getContextPath() + "/"));

   }
}

Inject beans and services into configuration using CDI

This example depends on the rewrite-integration-cdi module; you will need to include it as a dependency/JAR in your application.
Exhibit 4
public class ExampleConfigurationProvider extends HttpConfigurationProvider
{
   @Inject
   private RuleDatabase source;

   @Override
   public Configuration getConfiguration(final ServletContext context)
   {
      return ConfigurationBuilder.begin()
          .addRule()
          .when(new HttpCondition() {
             public boolean evaluate(HttpServletRewrite event, EvaluationContext context)
             {
                return source.includes(event.getRequest().getRequestURL());
             }
          })
          .perform(new HttpOperation() {
             @Override
             public void performHttp(HttpServletRewrite event, EvaluationContext context)
             {
                source.takeAction();
             }
          });
   }
}

Relocate resources using a Content Distribution Network (CDN)

The goal of a CDN is to serve content to end users with high availability and high performance, increasing the performance of websites that use them. Besides better performance and availability, CDNs also offload the traffic from your servers onto a server designed to quickly serve static files.
Exhibit 5
public class ExampleConfigurationProvider extends HttpConfigurationProvider
{

   @Override
   public Configuration getConfiguration(final ServletContext context)
   {
      return ConfigurationBuilder.begin()

          // Relocate jQuery to CDN
          .addRule(CDN.relocate("{p}jquery{s}.js")
                   .to("http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"))
          .where("p").matches(".*")
          .where("s").matches(".*")

          // Relocate custom CSS (or other outbound link) to a custom URL
          .addRule(CDN.relocate("{p}foo-{version}.css")
                   .to("http://mycdn.com/foo-{version}.css"));
          .where("p").matches(".*")
          .where("version").matches(".*")
   }
}

Secure resources using JAAS roles constraints

Exhibit 6
public class JaasRolesTestProvider extends HttpConfigurationProvider
{
   @Override
   public Configuration getConfiguration(final ServletContext context)
   {
      Configuration config = ConfigurationBuilder
               .begin()

               .addRule()
               .when(JAASRoles.required("admin", "privacy-monitor")
                        .and(Direction.isInbound())
                        .and(Path.matches("/admin/{tail}")))
               .perform(Forward.to("/internal/resource.jsp"))
               .where("tail").matches(".*");

      return config;
   }
}

Extending the configuration

When using the Rewrite Servlet module, most important configuration classes can be found in the org.ocpsoft.rewrite.servlet.config package. We continue to add new Conditions, Operations, and Rules, but you may always simply implement your own, or combine existing configuration objects to achieve a new result if something you are looking for does not exist. If you do, please help out the rest of the community and consider contributing your objects back to the project.

6 Comments

  1. rbento says:

    Please, if its possible, could you guys provide examples that:

    – receive a parameter and set it in a bean, like in #{ p : bean.p }

    – join a path and execute an action before redirecting. Pretty much like the ‘action’ tag in pretty config mapping.

    Thanks a lot

  2. Sure! Will do, for now, this should do:

    Join.path("/store/{p}").to("/resource.jsp").where("p").bindsTo(El.property("bean.p"))
  3. rbento says:

    Please, is there a way to set a session attribute with a parameter?

    For instance:

    This:

    Join.path("/store/{product}").to("/resource.jsp").withSessionBinding()

    Would perform:

    session.setAttribute("product", {product})

    Is there a way to get this behavior with 1.1.0.Final?

    The reason I’m asking this is because setting a parameter to requestParameterMap doesn’t work well with @ViewScope and ajax submissions to the same view.

    Once you perform the ajax request the param is gone from requestParameterMap. By setting the attribute to session would solve it.

    Other way would be binding the param to a EL property of a SessionScoped bean, but wouldn’t that be ugly?

  4. Jan says:

    Please could you give me some hints what is the recommended way to make prettyfaces domain sensitive? I am curious how to serve "microsites" in following pattern:

    I have applicatoin on main domain configured for prettyURL parameters like
    http://www.mainDomain.com/embed/#{lang}/microsite1/somestuff
    and want the same application serve
    http://www.microsite1.com/somestuff
    with the same jsf page

    It means capture server name microsite1 from request –> prepend /embed/#{lang}/microsite1/ according dynamic microsite configuration –> and let prettyconfig do it’s jobs.

    I want to keep http://www.microsite1.com/somestuff adress in browser and need #{lang} to be injected to JSF bean.

    Currently I am using prettyFaces 3.3. Is it possible to achieve this by prettyfaces and possible enhancements by Rewrite?

    Thank a lot for any advice.

  5. Oleg says:

    Hi,

    Assume, all my XHTML files are located in webapp under the folder "mod". I would like to avoid the need to type /mod/… in URLs. How can I rewrite URLs with the Rewrite, so that all requests get a prefix "mod" when resolving against real paths? For instance, when somebody types as URL

    .../views/list.jsf

    , it should be resolved (mapped) to

    .../mod/views/list.jsf

    .

    Thanks in advance.

  6. Andrey says:

    Hi

    Is there some "universal" configuration file, which makes JSF links human-readable by default?
    I mean all "/long_path/sample.jsf?id=10&name=tom" are automatically converted to "/sample/10/tom" in all auto-generated urls (including jsf 2.2 navigation model) and such links are processed correctly?

    I understand that there could be a problem in binding named parameters with URL fragments, but probably there’s some solution for this (like annotations)?

    Thanks in advance,
    Andrey

Leave a Comment




Please note: In order to submit code or special characters, wrap it in

[code lang="xml"][/code]
(for your language) - or your tags will be eaten.

Please note: Comment moderation is enabled and may delay your comment from appearing. There is no need to resubmit your comment.