April 7th, 2011 by Lincoln Baxter III

URL-rewriting in 60 seconds: JBoss Forge and PrettyFaces

Do you have an existing Maven-based Java EE application that you’d like to clean up a bit in the browser? Do your URLs look too much like this: http://example.com/app/sillyServletName/someStuff?sillyParam=22&sillyOtherParam=profile And not enough like this? http://example.com/app/profile/22 Are you building a new application, and don’t want to sacrifice anything when it comes to usability or SEO capabilities? Well, URL-rewriting is your answer, and it’s easy to get started, even easier using JBoss Forge. PrettyFaces is a URL-rewriting solution for Servlet, JavaEE, and JSF applications, is highly extendable, and easy to install; however, we weren’t satisfied with the experience of forcing people to create their own configuration file, trying to find which version to install, and having problems when they try to mix information from different sources. JBoss Forge looked like the perfect opportunity to make your job even easier, and it’s through JBoss Forge that we think we’ve accomplished our goals; we’d like to know if you agree:

Install PrettyFaces using JBoss Forge:

   _____                    
  |  ___|__  _ __ __ _  ___ 
  | |_ / _ \| '__/ _` |/ _ \  \\
  |  _| (_) | | | (_| |  __/  //
  |_|  \___/|_|  \__, |\___| 
                 |___/      
[no project] Desktop $ 
[no project] Desktop $ new-project --named prettyfaces-example-app  --topLevelPackage com.ocpsoft.prettyfaces
Use [~/Desktop/prettyfaces-example-app] as project directory? [Y/n] 
Wrote ~/Desktop/prettyfaces-example-app/src/main/resources/META-INF/forge.xml
***SUCCESS*** Created project [prettyfaces-example-app] in new working directory [~/Desktop/prettyfaces-example-app]
[prettyfaces-example-app] ~ $ 
[prettyfaces-example-app] ~ $ prettyfaces setup 
Wrote ~/Desktop/prettyfaces-example-app/src/main/webapp/WEB-INF/web.xml
Wrote ~/Desktop/prettyfaces-example-app/src/main/webapp/index.html
***SUCCESS*** Installed [forge.spec.servlet] successfully.
 
Install PrettyFaces for which technology?
 
  1 - [JSF 1.1 and Servlet <= 2.3]
  2 - [JSF 1.2 and Servlet >= 2.4]
  3 - [JSF 2.0 and Servlet >= 2.5]
  4 - [Java EE 6 and Servlet >= 3.0]*
 
Choose an option by typing the number of the selection [*-default]: 4
Install which version?
 
  1 - [com.ocpsoft:prettyfaces-jsf2:3.0.0]
  2 - [com.ocpsoft:prettyfaces-jsf2:3.0.1]
  3 - [com.ocpsoft:prettyfaces-jsf2:3.0.2-SNAPSHOT]
  4 - [com.ocpsoft:prettyfaces-jsf2:3.1.0]
  5 - [com.ocpsoft:prettyfaces-jsf2:3.1.1-SNAPSHOT]
  6 - [com.ocpsoft:prettyfaces-jsf2:3.2.0]
  7 - [com.ocpsoft:prettyfaces-jsf2:3.2.1-SNAPSHOT]*
 
Choose an option by typing the number of the selection [*-default]: 6
Wrote ~/Desktop/prettyfaces-example-app/src/main/webapp/WEB-INF/pretty-config.xml
***SUCCESS*** Installed [com.ocpsoft.forge.prettyfaces] successfully.
***SUCCESS*** PrettyFaces is configured.
[prettyfaces-example-app] ~ $
And now we create our first URL-mapping.
[prettyfaces-example-app] ~ $ prettyfaces mapping --pattern / --viewId /index.html -id index
Wrote ~/Desktop/prettyfaces-example-app/src/main/webapp/WEB-INF/pretty-config.xml
[prettyfaces-example-app] ~ $
With those three commands, we just created a new Servlet 3.0 web-application, installed PrettyFaces, and added a URL-mapping from ‘/’ to the index page. Now that’s powerful! Also, did I mention that this application is now ready to be deployed on a Servlet Container or Application Server like JBoss AS or Tomcat? Life is so hard these days…

So what does that mean? What actually happened?

First, no more hunting for configuration files or making sure that your XML has the right schema. Second, you no longer have to search for the available versions to install, and third, all of your POM configuration is done for you. In short, the prettyfaces-forge-plugin has set up the following configurations for you:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.ocpsoft.prettyfaces</groupId>
  <artifactId>prettyfaces-example-app</artifactId>
  <version>1.0.0-SNAPSHOT</version>
  <packaging>war</packaging>
 
...
  <dependencies>
    <dependency>
      <groupId>com.ocpsoft</groupId>
      <artifactId>prettyfaces-jsf2</artifactId>
      <version>3.2.0</version>
    </dependency>
  </dependencies>
...
</project>
And the PrettyFaces configuration file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<pretty-config xmlns="http://ocpsoft.com/prettyfaces/3.2.0" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ocpsoft.com/prettyfaces/3.2.0 
   http://ocpsoft.com/xml/ns/prettyfaces/ocpsoft-pretty-faces-3.2.0.xsd">
 
  <url-mapping id="index">
    <pattern value="/"/>
    <view-id value="/index.html"/>
  </url-mapping>
 
 
</pretty-config>
Sure, we could have created and updated these configurations ourselves, that’s pretty easy too, but this is just one more simplification; we want your lives to be as easy as possible. Even better, the PrettyFaces Plugin supports <TAB>-completion of mapping-IDs and view-IDs; when you type a command, you don’t have to look at the configuration file because most available options are just a <TAB> away. (When in doubt, press <TAB>)

What else does the PrettyFaces Forge Plugin give me?

  1. Automatic integration with JavaServer Faces (JSF) for page-load actions.
    [prettyfaces-example-app] ~ $ prettyfaces action --mappingId index 
          --methodExpression '#{auth.doAuth()}'
    ***INFO*** This feature requires JavaServer(tm) Faces.
    An action has requested to install the following facets into your project [forge.spec.jsf] continue? [Y/n] 
    Wrote ~/src/main/webapp/WEB-INF/faces-config.xml
    ***SUCCESS*** Installed [forge.spec.jsf] successfully.
    Wrote ~/src/main/webapp/WEB-INF/pretty-config.xml
    ***SUCCESS*** Added new action [action, phaseId="ANY_PHASE", onPostback="true"] for mapping [index]
    [prettyfaces-example-app] ~ $
    Which in turn updated our pretty-config.xml to include an action on the index page. Notice that we had to install JSF in order to continue. The action will only trigger if the page being executed is run through the FacesServlet.
      <url-mapping id="index">
        <pattern value="/"/>
        <view-id value="/index.html"/>
        <action>#{auth.doAuth()}</action>
      </url-mapping>
  2. Install Multi-page Faces Messaging support (preserve messages over navigation redirects.)
    [prettyfaces-example-app] ~ $ prettyfaces faces-message-propagation INSTALL
    Wrote ~/src/main/webapp/WEB-INF/faces-config.xml
    ***SUCCESS*** MultiPageMessagesListener is installed.
    [prettyfaces-example-app] ~ $
    This updates our faces-config.xml file to include our provided PhaseListener.
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <faces-config xmlns="http://java.sun.com/xml/ns/javaee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">
      <lifecycle>
        <phase-listener>com.ocpsoft.forge.pretty.faces.event.MultiPageMessagesSupport</phase-listener>
      </lifecycle>
    </faces-config>
  3. List all configured URL-mappings:
    [prettyfaces-example-app] ~ $ prettyfaces list-mappings {--all}
    / -> /index.html [id=index, outbound=true]
    /login -> /LoginServlet/doLogin [id=login, outbound=true]
    [prettyfaces-example-app] ~ $
  4. Remove URL-mappings:
    [prettyfaces-example-app] ~ $ prettyfaces remove-mapping --id 
    index    login    
    [prettyfaces-example-app] ~ $ prettyfaces remove-mapping --id login 
    Wrote ~/src/main/webapp/WEB-INF/pretty-config.xml
    ***SUCCESS*** Removed UrlMapping [ id=login, pattern=/login, parentId=, viewId=/LoginServlet/doLogin, actions=[], outbound=true, parser=null, pathValidators=[], queryParams=[]]
    [prettyfaces-example-app] ~ $
  5. Notice that we have support for <TAB> completion of URL-mapping IDs, so you can just press <TAB> if you need to see available options.

Conclusion

Please note that you can also use all of the tools described here on an existing Maven-based web application, and you do not need to create a new project just to try this. We hope that this simple plugin makes your life a little bit easier, and more productive. We also welcome your feedback. Tell us how we can improve! For those who are curious, the source code for the PrettyFaces Forge Plugin is located here, on GitHub.
Lincoln Baxter, III

About the author:

Lincoln Baxter, III is a Principal Software Engineer at Red Hat, working on JBoss open-source projects; most notably as creator & project lead of JBoss Forge, and author of Errai UI. This blog represents his personal thoughts and perspectives, not necessarily those of his employer.

He is a founder of OCPsoft, the author of PrettyFaces and Rewrite, the leading URL-rewriting extensions for Servlet, Java EE, and Java web frameworks; he is also the author of PrettyTime, social-style date and timestamp formatting for Java. When he is not swimming, running, or playing Ultimate Frisbee, Lincoln is focused on promoting open-source software and making web-applications more accessible for small businesses, individuals.

Posted in Java, JBoss, OpenSource, PrettyFaces, Seam

3 Comments

  1. Shital says:

    Not able to install prettyfaces plugin with JBoss Forge, version [ 1.0.0.Beta5 ]

    When I try: forge install-plugin ocpsoft-prettyfaces
    forge freezes after following messages:

    Connecting to remote repository [https://raw.github.com/forge/plugin-repository/master/repository.yaml]… connected!
    ***INFO*** Preparing to install plugin: ocpsoft-prettyfaces
    ***INFO*** Checking out plugin source files to [/var/folders/Go/GoMfQXVfFhq8PGXmRajrfk++eCM/-Tmp-/forgetemp4928299912121450623/repo] via ‘git’
    Receiving objects: 100% (294/294)
    Resolving deltas: 100% (93/93)
    ***INFO*** Switching to branch/tag [1.0.0.Beta5]

    1. Shital says:

      Never mind. It was just taking time before going to the next step. Case of fast fingers :-)

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.