Sunday, September 18, 2011

Single class pure Java JSF application

In my previous blog entry, Authoring JSF pages in pure Java, it was explained how to set up a JSF based web application using nothing but pure Java. No XML based templating (Facelets) was required and the view was build purely programmatically.

I got one remark though that the example code did used expression language (EL) to patch some of the parts together. Although EL is really convenient, as it provides a way to point to a (nested) method on a scoped object, it's not regular type-safe Java.

Luckily, the Java component API of JSF doesn't only use EL based ValueExpressions and MethodExpressions, but also allows regular Java types to be set as listeners and values. This is demonstrated in the code below. While at it, I've done away with the separate backing bean for this example and let the same class that defines the page handle the action event.

The result is a pure Java, xml-less, EL-less, config-less, single class JSF application [phew]:

@Named
@FacesConfig
public class Intro implements Page, ActionListener {

    private HtmlOutputText message;
    
    @Override
    public void buildView(FacesContext context, UIViewRoot root) throws IOException {
        
        List rootChildren = root.getChildren();
        
        UIOutput output = new UIOutput();
        output.setValue("<html xmlns="http://www.w3.org/1999/xhtml">");                
        rootChildren.add(output);
        
        HtmlBody body = new HtmlBody();
        rootChildren.add(body);
        
        HtmlForm form = new HtmlForm();
        body.getChildren().add(form);
        
        message = new HtmlOutputText();
        form.getChildren().add(message);
        
        HtmlCommandButton actionButton = new HtmlCommandButton();
        actionButton.addActionListener(this);
        actionButton.setValue("Do action");
        form.getChildren().add(actionButton);
                
        output = new UIOutput();
        output.setValue("</html>");
        rootChildren.add(output);
    }
    
    @Override
    public void processAction(ActionEvent event) throws AbortProcessingException {
        message.setValue("hello, world");
    }    
}

To run this on Payara, only this class and the small (8,980 bytes) javavdl.jar library are required:

After requesting localhost:8080/demo/intro.jsf, a single button will be shown. The message "hello, world" will be displayed when this button is clicked.

Interesting to note perhaps is that the components themselves only exist for the duration of the request and after every post-back the component tree will be re-created. State set on the components during buildView will be marked as the so-called initial state and will typically not be taken into account by JSF's state saving mechanism. Since only the HtmlCommandButton in the example code references the Page instance after this buildView it will effectively have request scope.

The java based vdl is still rather simple, so it's still just a proof of concept. I've planned some enhancements that I'll work on soon if time permits (e.g. perhaps support for scopes other than request scope without using EL). Stay tuned!

Arjan Tijms

Monday, September 12, 2011

Authoring JSF pages in pure Java

JSF is well known as a server side web framework to build a web application's UI with the help of components. For the overwhelming majority of users those components are represented by the tags one uses to compose a page, be it via JSP or Facelets.

The following is a typical example of a page authored with Facelets:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">    
    <h:body>   
       #{backingBean.hello}   
        <h:form>      
            <h:inputText value="#{backingBean.name}" />                    
            <h:commandButton value="Say Hello" action="#{backingBean.sayHello}" />
        </h:form>        
    </h:body>
</html>

This may give the impression that JSF components *are* the tags shown above, and thus that JSF is necessarily about tags and XML. That is however not true.

JSF has always had a clear separation between the technology used to author pages (the so-called view description language) and the actual API to create components and compose them together into a component tree. This API is a Java API that even in the very first days of JSF had no knowledge whatsoever about JSP or tags. The strict separation allowed alternative view declaration languages like Facelets to be created and eventually be promoted to the default VDL, without needing to change the underlying JSF core framework.

Other view declaration languages have been created as well. One notable example is a concept based on JavaFX, in which a JSF page would look like this:

var x = 0;
var bindVal = "Hello";
 
function init(){
   FxPage{
      content : [
         FxForm{
                content : [
                    FxOutputLabel{
                        value : bind bindVal
                    },
                    FxCommandButton{
                        value : "Button"
                        actionListener : function() : String{
                            bindVal = "Hello {x++}";
                            return null;
                        }
                    }
                ]
            }
        ]
    }
}
See: JavaFX as JSF VDL (View Description Language)?

As it appears, the API to create components and compose a component tree is pretty accessible by itself. It could theoretically be used directly to author pages instead of solely being used as an API for VDL implementations. The problem however is that it's not clear how to actually start doing that. One trick is to use dynamic tree manipulation and add components in a PreRenderView event on an otherwise empty page.

Another way is to create a minimal VDL implementation. As a proof of concept, that's what I did. With such a thing it's possible to create a JSF application completely in Java. No Facelets or JSP files, and following Minimal 3-tier Java EE app, without any XML config, no web.xml or faces-config.xml is required either. There doesn't even have to be a WEB-INF or WebContent directory in the project.

The following shows a JSF page being defined in pure Java:

public class Intro implements Page {

    @Override
    public void buildView(FacesContext context, UIViewRoot root) throws IOException {

        ELContext elContext = context.getELContext();
        ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();
        
        List<UIComponent> rootChildren = root.getChildren();
        
        UIOutput output = new UIOutput();
        output.setValue("<html xmlns="http://www.w3.org/1999/xhtml">");                
        rootChildren.add(output);
        
        HtmlBody body = new HtmlBody();
        rootChildren.add(body);
        
        HtmlForm form = new HtmlForm();
        body.getChildren().add(form);
        
        ValueExpression messageProperty = expressionFactory.createValueExpression(elContext, "#{myBean.message}", String.class);
        
        HtmlOutputText message = new HtmlOutputText();
        message.setValueExpression("value", messageProperty);
        form.getChildren().add(message);

        MethodExpression helloMethod = expressionFactory.createMethodExpression(elContext, "#{myBean.action}", Void.class, new Class[0]);
        
        HtmlCommandButton hiCommand = new HtmlCommandButton();
        hiCommand.setActionExpression(helloMethod);
        hiCommand.setValue("Say hello");
        form.getChildren().add(hiCommand);
        
        MethodExpression navigateMethod = expressionFactory.createMethodExpression(elContext, "#{myBean.navigate}", String.class, new Class[0]);
        
        HtmlCommandButton navigateCommand = new HtmlCommandButton();
        navigateCommand.setActionExpression(navigateMethod);
        navigateCommand.setValue("Do navigation");
        form.getChildren().add(navigateCommand);
                
        output = new UIOutput();
        output.setValue("</html>");
        rootChildren.add(output);
    }    
}

This will be rendered as follows:

The code shows how components are created simply by using the new operator and a tree is created by just inserting the child components in the children collections of their parents. Action listeners are registered on action source components by setting a method expression that points to the scoped backing bean "myBean", which is defined as follows:

@Named
@FacesConfig
public class MyBean {

    private String message;

    public void action() {
        message = "Hi!";
    }
    
    public String navigate() {
        return redirectOutcome(OtherPage.class);
    }
    
    public String getMessage() {
        return message;
    }    
}

Note that the bean features a navigation method that uses the class type of the target page to determine the navigation outcome.

By putting stuff in base classes or utility methods, page implementations can be simplified. For instance, the following shows the page where the user is navigated to after pushing the button on the first page. It inherits from a base class that already defines the html and outer body part, and only implements the body content:

public class OtherPage extends BodyTemplate {

    @Override
    public void buildBody(FacesContext context, HtmlBody body) {    
        HtmlOutputText output = new HtmlOutputText();
        output.setValue("This is a new page.");
        body.getChildren().add(output);        
    }
}

This page is rather simple and is rendered as:

As shown by the screen shots, if the project is called javavdl the initial page can be requested by requesting http://localhost/javavdl/intro.jsf, which is fully implemented using the Intro.java class given above. After clicking the navigate button, the user will be redirected to http://localhost/javavdl/test/otherPage.jsf, which is fully implemented by OtherPage.java. For this simple proof of concept, classes implementing pages have to reside in the package resources.javavdl.pages. Sub-packages in that package become paths relative to the deployment root of the application. E.g. /test/otherPage.jsf is implemented by resources.javavdl.pages.test.OtherPage.

The following is a picture of my workspace, showing that there is absolutely not a single xml file:

If this were used for real, the "src" package would probably be in a jar, and the application would consist of nothing more than this jar and the four classes shown in the demo package.

The current setup is really just a proof of concept. I personally think a declarative approach like Facelets is actually clearer, although some people actually do seem to like a purely programmatic approach to building a UI.

If people want to tinker with this, I've shared my Eclipse project where I implemented this here: github.com/arjantijms/javavdl (it currently depends on the Glassfish WTP server adapter being installed).

Arjan Tijms

Sunday, September 4, 2011

Simple Java based JSF custom component

Even though in JSF components have always been a central thing, actually creating them required a ridiculous amount of tedious work in JSF 1.x. Not only did you had to create the actual component, it also required you to:
  • Register the component in an XML file
  • Create a tag handler class, where you referenced the component by its registered name
  • Register the tag in .tld file.

You were also more or less supposed to create a separate renderer class, and although this actually has always been optionally, people seemed to interpret it as being a required part as well. Although none of this was really difficult, the sheer amount of work prevented everyone but component library builders from creating components.

JSF 2.0 addressed all of these concerns by introducing composite components, where you are able to create first-class components just by putting some existing components and/or markup in a Facelets file. For the majority of use cases where application builders needed their own customized components, this is actually all that's needed.

For some cases however a Java based component is still a more natural fit. Although not as simple to create as composite components, creating Java based custom components has actually been simplified as well. Of the steps outlined above, only a registration for the tag is still required. The actual component can be rather simple:

components/CustomComponent.java

@FacesComponent("components.CustomComponent")
public class CustomComponent extends UIComponentBase {

    @Override
    public String getFamily() {        
        return "my.custom.component";
    }
    
    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        
        String value = (String) getAttributes().get("value");
        
        if (value != null) {        
            ResponseWriter writer = context.getResponseWriter();
            writer.write(value.toUpperCase());
        }
    }
}

Unfortunately, a registration in an XML file is still required in JSF 2.1 to use this as a tag (note, that in JSF 2.2 this isn't required anymore):

META-INF/my.taglib.xml

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
    version="2.0">

    <namespace>http://example.com/test</namespace>
    
    <tag>
        <tag-name>customComponent</tag-name>
 <component>
            <component-type>components.CustomComponent</component-type>
        </component>
    </tag>
    
</facelet-taglib>

The custom component can now be used on a Facelet as follows:

page.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:test="http://example.com/test"
>
    <h:body>     
        <test:customComponent value="test"/>        
    </h:body>
</html>

As shown, creating a Java based JSF component that simply renders something is not that complicated. Although composite components should generally be preferred, Java based ones can come in handy and it's an important extra tool.

It's a shame perhaps the XML registration is still needed in JSF 2.1, but luckily there was a feature request in the JSF spec JIRA that made it largely unnecessary for JSF 2.2. Hopefully the actual Java code can also be further simplified if the family and component name would be defaulted in a future JSF version (the last e.g. to the fully qualified class name).

Arjan Tijms