link:../index.asciidoc[← Docs Index] link:./index.asciidoc[ ← Migration]

= PrettyFaces 3.x Migration Guide
Christian Kaltepoth
:description: This guide described the process of migrating existing PrettyFaces applications to Rewrite
:keywords: PrettyFaces, Rewrite, Migration

= PrettyFaces 3.x Migration Guide

This guide describes how to migrate existing applications built using PrettyFaces 3.x to Rewrite 2.0.

== Migration strategies

There are basically two ways of migrating such applications to Rewrite:

PrettyFaces compatibility module:: This Rewrite module allows you to keep your old PrettyFace 3.x
  configuration and use it with Rewrite. The module supports both the XML configuration file
  +pretty-config.xml+ and the PrettyFaces annotations like +@URLMapping+. You should use this way
  of migration for your application if you don't want to modify your existing code.

JSF integration module:: If you don't want to use the old PrettyFaces 3.x configuration anymore and
  want to use all the new features of Rewrite, you should choose the Rewrite JSF integration module. 
  This module provides a new way of configuration and therefore requires you to adapt your 
  existing configuration.

NOTE: Both ways of migrating will only work for JSF 2.x applications.

The following sections will describe both ways in detail.

== Strategy #1: PrettyFaces compatibility module

Migrating application using PrettyFaces 3.x is very easy. Just follow the steps described below.

=== Update your dependencies

First you have to remove the old `com.ocpsoft.prettyfaces` dependency from your project. Open
your +pom.xml+ and remove the following entry:

[source,xml]
----
<dependency>
   <groupId>com.ocpsoft</groupId>
   <artifactId>prettyfaces-jsf2</artifactId>
   <version>3.3.3</version>
</dependency>
----

Now add the Rewrite servlet and the PrettyFaces compatibility module to your +pom.xml+:

[source,xml]
----
<dependency>
   <groupId>org.ocpsoft.rewrite</groupId>
   <artifactId>rewrite-servlet</artifactId>
   <version>${rewrite.version}</version>
</dependency>
<dependency>
   <groupId>org.ocpsoft.rewrite</groupId>
   <artifactId>rewrite-integration-faces</artifactId>
   <version>${rewrite.version}</version>
</dependency>
<dependency>
   <groupId>org.ocpsoft.rewrite</groupId>
   <artifactId>rewrite-config-prettyfaces</artifactId>
   <version>${rewrite.version}</version>
</dependency>
----

Your code should still compile fine after updating the dependencies.


=== Filter registration

If you used PrettyFaces in a Servlet 3.0 environment, the required servlet filter is automatically 
registered. In this case you typically don't have an entry for the +PrettyFilter+ in your +web.xml+
and you can therefore skip this section.

If you added the +PrettyFilter+ manually to your +web.xml+, you will have to replace the filter
declaration to use the Rewrite filter instead. Locate the following entry in your +web.xml+:

[source,xml]
----
<filter>
   <filter-name>Pretty Filter</filter-name>
   <filter-class>com.ocpsoft.pretty.PrettyFilter</filter-class>
   <async-supported>true</async-supported>
</filter>
<filter-mapping> 
   <filter-name>Pretty Filter</filter-name> 
   <url-pattern>/*</url-pattern> 
   <dispatcher>FORWARD</dispatcher>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>INCLUDE</dispatcher>
   <dispatcher>ASYNC</dispatcher>
   <dispatcher>ERROR</dispatcher>
</filter-mapping>
----

Remove this entry completely and replace it with the corresponding entry for the +RewriteFilter+:

[source,xml]
----
<filter>
   <filter-name>OCPsoft Rewrite Filter</filter-name>
   <filter-class>org.ocpsoft.rewrite.servlet.RewriteFilter</filter-class>
   <async-supported>true</async-supported>
</filter>
<filter-mapping>
   <filter-name>OCPsoft Rewrite Filter</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>FORWARD</dispatcher>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>INCLUDE</dispatcher>
   <dispatcher>ASYNC</dispatcher>
   <dispatcher>ERROR</dispatcher>
</filter-mapping>
----

NOTE: Please note that if you are using a Servlet 3.x container and your +web.xml+ doesn't set
+metadata-complete="true"+, you don't have to register the Rewrite filter manually, because
this is done automatically. In this case just make sure to remove the old +PrettyFilter+ entry. 

=== Test your application

After having performed the changes described in the two sections, your migration is complete.
Although we consider the compatibility module to be very solid and stable, you should test your 
application carefully. If something doesn't work as before, let us know. :) 

== Strategy #2: JSF integration module

This section describes how to migrate existing PrettyFaces configuration to the Rewrite
JSF integration module.

=== Adding the Rewrite dependencies

If you want to use the Rewrite JSF integration module, you have to add the following dependencies
to your project.

[source,xml]
----
<!-- Rewrite with JSF integration -->
<dependency>
   <groupId>org.ocpsoft.rewrite</groupId>
   <artifactId>rewrite-servlet</artifactId>
   <version>${rewrite.version}</version>
</dependency>
<dependency>
   <groupId>org.ocpsoft.rewrite</groupId>
   <artifactId>rewrite-integration-faces</artifactId>
   <version>${rewrite.version}</version>
</dependency>

<!-- optional: CDI integration -->
<dependency>
   <groupId>org.ocpsoft.rewrite</groupId>
   <artifactId>rewrite-integration-cdi</artifactId>
   <version>${rewrite.version}</version>
</dependency>
----

Adding the dependencies in a Servlet 3.0 environment will automatically register the required
Servlet listeners and filters.

=== PrettyFaces XML configuration

PrettyFaces used an XML file called +pretty-config.xml+ to configure URL mappings and rewrite rules.
Rewrite uses a fluent Java API for configuration instead. XML files are not supported any more.

----
public class MyConfigurationProvider extends HttpConfigurationProvider {

  @Override
  public Configuration getConfiguration(ServletContext context) {
  
     return ConfigurationBuilder.begin()
               
               /* add your rules here */

               ;
  }

  @Override
  public int priority() {
     return 10;
  }

}
----

==== URL Mappings

The URL mappings of PrettyFaces have been replace with a Rewrite rule called +Join+. 
The concepts are very similar. You can specify a _virtual path_ that is mapped to a
physical server resource.

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
<url-mapping id="login">
  <pattern value="/login" />
  <view-id value="/login.jsf" /> 
</url-mapping>
----
|
----
@Override
public Configuration getConfiguration(ServletContext context) {
  
   return ConfigurationBuilder.begin()

             .addRule(Join.path("/login").to("/login.jsf"))
             
             ;
}
|===

==== Path Parameters

Path parameters are dynamic parts of an URL which you typically use to embed details about an addressed
resource. With PrettyFaces you had to use EL-like expressions in the pattern part of the mapping to
add such parameters. Rewrite parameters are very similar to that.  The only real difference is that 
you have to use +\{param\}+ instead of +#\{param\}+ for the parameter. 

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
<url-mapping id="viewCategory">
  <pattern value="/store/#{category}/" />
  <view-id value="/faces/shop/store.jsf" /> 
</url-mapping>
----
|
----
.addRule(
  Join.path("/store/{category}/").to("/faces/shop/store.jsf")
)
|===

In the example show above the parameters will be automatically turned into query parameters with
the same name as the parameter. This means that you can access the parameter using the standard
Servlet API:

----
request.getParameter("category");
----

Instead of using the standard Servlet API to access the parameters, it is often easier
to use EL-injected path parameters. With PrettyFaces you would simply use an EL expression that
refers to a bean property for that. PrettyFaces will then automatically inject the path parameter
value into that bean property.

Rewrite uses a concept called _parameter bindings_ to achieve the same. With Rewrite you can
_bind_ parameters to bean properties by calling +.where("param").bindsTo(...)+. See the following
code for an example: 

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
<url-mapping id="viewCategory">
  <pattern value="/store/#{bean.category}/" />
  <view-id value="/faces/shop/store.jsf" /> 
</url-mapping>
----
|
----
.addRule(
  Join.path("/store/{category}/").to("/faces/shop/store.jsf")
).where("category").bindsTo(El.property("bean.category"))
|===

If your bean uses a JSF-specific scope like +@ViewScoped+), you have to wrap 
the +El+ binding in a +PhaseBinding+. This will tell PrettyFaces to submit the 
binding in the specified JSF phase which ensures, that the scope of the bean will
be active.

So instead of:

----
.bindsTo(El.property("bean.category"))
----

You have to write:

----
.bindsTo(PhaseBinding.to(El.property("bean.category"))).after(PhaseId.RESTORE_VIEW))
----

==== Page actions

PrettyFaces allowed the user to specify a _page action_ which is invoked when a request
for the mapping is received. 


[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
<url-mapping id="viewItem">
  <pattern value="/store/item/#{id}/" />
  <view-id value="/faces/shop/item.jsf" /> 
  <action>#{bean.loadItem}</action>
</url-mapping>
----
|
----
.addRule(
  Join.path("/store/item/#{id}/").to("/faces/shop/item.jsf")
).perform(Invoke.binding(El.retrievalMethod("bean.loadItem")))
|===

With the Rewrite configuration shown above, the page action is invoked very early in request 
processing, even before the JSF lifecycle starts. In some situations this may lead to problems.
Especially if you are using a scope like +@ViewScoped+, which requires an active JSF
lifecycle.

To work around this problem, you can defer the invocation of the page action by wrapping it in
a +PhaseOperation+. 

So instead of:

----
.perform(
  Invoke.binding(El.retrievalMethod("bean.loadItem"))
)
----

You have to write:

----
.perform(
  PhaseOperation.enqueue(
    Invoke.binding(El.retrievalMethod("bean.loadItem"))
  ).after(PhaseId.RESTORE_VIEW)
)

----




=== PrettyFaces Annotations

==== URL Mappings

As the URL mappings of PrettyFaces have been replaced with +Join+, the replacement
for the +@URLMapping+ annotation is called +@Join+. 

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
@URLMapping(pattern = "/login", viewId = "/login.jsf")
public class CustomerDetailsBean {
  ...
}
----
|
----
@Join(path = "/login", to="/login.jsf")
public class CustomerDetailsBean {
  ...
}
|===

==== Path parameters

With PrettyFaces, path parameters were specified using EL-like expressions in the pattern.
With Rewrite you simply specify the parameter in the path pattern using +\{name\}+. Rewrite
automatically transforms the value into a query parameter with the same name. you can also
directly inject the value into your bean by adding the +@Parameter+ annotation to a field
with the same name as the parameter. 

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
@URLMapping(
	pattern = "/customer/#{ id : customerDetailsBean.id }", 
	viewId = "/customer-details.jsf")
public class CustomerDetailsBean {

  private Long id;

}
----
|
----
@Join(path = "/customer/{id}", to="/customer-details.jsf")
public class CustomerDetailsBean {

  @Parameter
  private Long id;

}
|===

If you want to customize the regular expression that is used to match the parameter, just add
a +@Matches+ annotation:

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
@URLMapping(
	pattern = "/customer/#{ /[0-9]+/ customerDetailsBean.id }", 
	viewId = "/customer-details.jsf")
public class CustomerDetailsBean {

  private Long id;

}
----
|
----
@Join(path = "/customer/{id}", to="/customer-details.jsf")
public class CustomerDetailsBean {

  @Parameter
  @Matches("[0-9]+")
  private Long id;

}
|===


==== Query parameters

Query parameters in Rewrite are handled the same way as path parameters. To inject the value
of a query parameter into your bean, add a +@Parameter+ to a field like this.

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
@URLMapping(pattern = "/login", viewId = "/login.jsf")
public class CustomerDetailsBean {

  @URLQueryParam("q")
  private String query;

}
----
|
----
@Join(path = "/login", to="/login.jsf")
public class CustomerDetailsBean {

  @Parameter("q")
  private String query;

}
|===

TIP: You can omit the parameter name when using the +@Parameter+ annotation if the name of the query
     parameter is the same as the name of the field.


==== Page actions


To invoke a specific method in your bean when the page is accessed, add a +@RequestAction+ annotation
to the method. 

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
@URLMapping(pattern = "/login", viewId = "/login.jsf")
public class CustomerDetailsBean {

   @URLAction
   public void action() {
      ...
   }

}
----
|
----
@Join(path = "/login", to="/login.jsf")
public class CustomerDetailsBean {

  @RequestAction
  public void action() {
     ...
  }

}
|===

The +ignorePostback+ attribute is now a separate annotation called +@IgnorePostback+.

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
@URLAction(onPostback=false)
public void action() {
  ...
}
----
|
----
@RequestAction
@IgnorePostback
public void action() {
  ...
}
|===

TIP: The +@IgnorePostback+ annotation can also be used with +@Parameter+.

If the annotated bean has a scope that requires an active JSF lifecycle like for example
+@ViewScope+, you have to _defer_ the invocation so that it is executed within the JSF lifecycle. 
To do so add a +@Deferred+ annotation to the method.  

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
@ManagedBean
@ViewScoped
@URLMapping(pattern = "/login", viewId = "/login.jsf")
public class CustomerDetailsBean {

   @URLAction
   public void action() {
      ...
   }

}
----
|
----
@ManagedBean
@ViewScoped
@Join(path = "/login", to="/login.jsf")
public class CustomerDetailsBean {

  @RequestAction
  @Deferred
  public void action() {
     ...
  }

}
|===

=== Creating links

PrettyFaces shipped with a special JSF component that simplified creating links to mapped URLs.
However JSF 2.0 introduced +<h:link>+, which works fine for creating such links. Rewrite doesn't
include any special JSF component. It is recommended to use the standard JSF component for rendering
links.

Using +<h:link>+ for creating links to Rewrite URLs is very easy. Just use the URL you
configured as the +to+ part of the Join for the +outcome+. If the URL contains parameters,
set their value using +<f:param>+.

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
<pretty:link mappingId="customerDetails">
  <f:param value="123" />
  Show details
</pretty:link>
----
|
----
<h:link outcome="/customer-details.jsf">
  <f:param name="id" value="123"/>
  Show details
</h:link>
|===


=== Programmatic navigation

Programmatic navigation was very painful in PrettyFaces. To navigate to a page with path or
query parameters, you had to obtain a reference to the bean which the parameters were bound
to, set them to the desired values and return a PrettyFaces navigation string.

With Rewrite you can use the new +Navigate+ class, which provides a fluent way for navigation.
Just change your action method to return +Navigate+ instead of a string. 
Then use +Navigate.to(..)+ to select the target view. You can either supply a class annotated
with +@Join+ or specify the +to+ part of a join for that. Then you can use +with()+ to set the
values of the query or path parameters.

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
public String actionMethod() {
  // obtain the CustomerDetailsBean
  customerDetailsBean.setId("123");
  return "pretty:customerDetails";
}
----
|
----
public Navigate actionMethod() {
  return Navigate.to(CustomerDetailsBean.class)
      .with("id", "123");
}
|===

Referencing the page you want to navigate to using a class only works if you are using
the Rewrite +@Join+ annotation. If you are using the +ConfigurationProvider+ API for 
configuration, you can reference the page using the JSF view-id like this:

[cols="1a,1a", options="header"]
|===
|PrettyFaces
|Rewrite
| 
----
public String actionMethod() {
  // obtain the CustomerDetailsBean
  customerDetailsBean.setId("123");
  return "pretty:customerDetails";
}
----
|
----
public Navigate actionMethod() {
  return Navigate.to("/customer-details.xhtml")
      .with("id", "123");
}
|===


If you used the JSF 2.0 implicit navigation for navigating with PrettyFaces,
you can do so in Rewrite too.

----
public String actionMethod() {
  return "/customer-details.jsf?faces-redirect=true&id=123";
}
----