Skip to main content

JSF Tip #56 - Using the action based prototype in Mojarra

Posted by mriem on January 13, 2014 at 7:19 PM PST

The JavaEE team at Oracle has been busy processing the feedback from the JavaEE 8 Community Survey

Question 6 in part one of the survey reads: "Is there any one de-facto standard technology in this space [Server side web MVC framework, aside from JSF] to which we should look for inspiration". For those respondents that answered yes to that question, fully half of them cited Spring MVC. By way of background, it's possible to classify server side web frameworks as "action based" or "component based". For some background on these terms, please see http://javaserverfaces.java.net/presentations/demystifyingjsf.odp.

To explore the possibilities for adding "action based" to the UI standard for JavaEE, we have committed some experimental prototype work to snapshot builds of Mojarra on January 9th, 2014. The current prototype allows you to use a simple annotation which would result in a call to a method on your managed bean and then dispatch the response to a regular view.

To try out the code in this blog entry, grab the latest 2.2.6-SNAPSHOT build of Mojarra from the maven.java.net snapshot repository and drop it into the GlassFish 4.0 modules directory.

You will also need to add the following dependency in the POM of your web application.

<dependency>
  <groupId>org.glassfish</groupId>
  <artifactId>javax.faces</artifactId>
  <version>2.2.6-SNAPSHOT</version>
  <scope>provided</scope>
</dependency>

Our example bean

import com.sun.faces.action.RequestMapping;
import javax.enterprise.context.RequestScoped;
import java.io.Serializable;
import javax.faces.context.FacesContext;
import javax.inject.Named;

@Named("myBean")
@RequestScoped
public class MyBean implements Serializable {
    private String value;

    @RequestMapping(value = "/form1b.xhtml")
    public String form1() {
        String inputText1 = (String) FacesContext.getCurrentInstance().
                getExternalContext().getRequestParameterMap().get("inputText1");
        setValue("We set inputText1 manually to - " + inputText1);
        return "/form1b.xhtml";
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }
}

Note the request mapping here is an exact mapping, but you can also do an extension mapping (using *.xx) or a prefix mapping do (using prefix/*).

Our example page (using HTML syntax)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Facelet HTML page</title>
    <head>
    <body>
        <form action="#{request.contextPath}/action/form1b.xhtml">
            <input id="inputText1" value="#{myBean.value}"/>
            <input id="submit" type="submit" value="Submit"/>
        </form>
    </body>
</html>

Our example page (using JSF syntax)

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <form action="#{request.contextPath}/action/form1b.xhtml">
            <h:inputText id="inputText1" value="#{myBean.value}"/>
            <input id="submit" type="submit" value="Submit"/>
        </form>
    </h:body>
</html>

The example result page (using HTML syntax)

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>Result page</title>
    </head>
    <body>
        We did a POST to an action based URL and the result is:
        #{myBean.value}
    </body>
</html>

The example result page (using JSF syntax)

<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <h:head>
        <title>Result page</title>
    </h:head>
    <h:body>
        We did a POST to an action based URL and the result is:
        <h:outputText value="#{myBean.value}"/>
    </h:body>
</html>

The relevant configuration in web.xml

    <servlet>
        <servlet-name>Faces Action Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <init-param>
            <param-name>javax.faces.LIFECYCLE_ID</param-name>
            <param-value>com.sun.faces.action.ActionLifecycle</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>     
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>     
    <servlet-mapping>
        <servlet-name>Faces Action Servlet</servlet-name>
        <url-pattern>/action/*</url-pattern>
    </servlet-mapping>   
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>

While not necessary we opted to include the regular mapping to the FacesServlet to demonstrate that the "action based" approach can coexist in a JSF web application.

Note as this code is in SNAPSHOT mode it means we might need to do some code adjustments, so consider these code samples as examples of what we might or might not be working towards. Feel free to give feedback in the comments!

And that is it.

Enjoy!

Related Topics >>

Comments

This post is great but things like {code} String ...

This post is great but things like
{code}
String inputText1 = (String) FacesContext.getCurrentInstance().
getExternalContext().getRequestParameterMap().get("inputText1");
{code}
should be easier IMHO.

Being able to validate input params in the form1 method would be nice too.

As this is a prototype we have not done the work to make ...

As this is a prototype we have not done the work to make that easier yet, but in a subsequent commit we are thinking to support the following:

@RequestMapping(value = "/form1b.xhtml")
public String form1( @RequestParam("inputText1") String inputText1 ) {
setValue("We set inputText1 manually to - " + inputText1);
return "/form1b.xhtml";
}

That would make it more concise.

Then should we combine jsf and jax-rs?

Then should we combine jsf and jax-rs?

If you introduce something in JSF, please also introduce ...

If you introduce something in JSF, please also introduce request param mappings like this:

@RequestMapping(...)
public void doSomething(@RequestParameter String test, @RequestParameter(name="userId") Long id)

Also support for conversion and validation are required!

Right, see my previous comment about working on supporting that!

Right, see my previous comment about working on supporting that!