Showing posts with label JSF. Show all posts
Showing posts with label JSF. Show all posts

Thursday, July 22, 2010

Determine Which Row is Selected in a JSF Table

Let's say you have a JSF table with numerous rows, and that when one of them is "selected" you'd like to know which one it is. Let's assume a JSF event is fired off when you click on the row, resulting in a callback to your application. In this callback, you want to determine the identity of the row in a way that correlates to your application, such that you can proceed with whatever action is needed. Here's the sequence:
  1. Table is constructed with rows representing application objects A, B and C
  2. User clicks somewhere in row B, e.g. in an input text box
  3. JSF event fires and your application is called back
  4. The application determines that B has been selected and processes that application object as needed
Now the obvious way to "determine that B has been selected" would be to simply set the ID attribute for each row to an identifying value at table construction time. But, using such variables for the ID attribute is not allowed in JSF. Don't ask me why. Here's one way to get around this:
  1. Add a parameter to the UIComponent with the identity as needed
  2. Register an interest in the JSF event that will get fired when the UIComponent is selected
  3. Examine the event received in your application callback to find the UIParameter child
  4. Examine the UIParameter to extract the identity of the row
The code snippets, first for the JSF markup addressing step #1 and #2. Note that I'm using IceFaces, setting the per-row variable for use in each UIComponent comprising each row:
<ice:dataTable 
     var="thisRow"
     value="#{app.allRows}"
    ....
>
....
    <ice:inputText valueChangeListener="#{app.callback}">
        <f:param name="name" value="#{thisRow.id}"/>
    </ice:inputText>
....
</ice:dataTable>
Here are steps #3 and #4, the application callback:
public void callback(ValueChangeEvent event) { 

    for (UIComponent child : event.getComponent().getChildren()) {
        if (child instanceof UIParameter) {
            UIParameter param = (UIParameter) child;
            if ("name".equals(param.getName())) {
                String thisID = (String)param.getValue();
                if (thisID.equals(theIDofInterest)) {
                    // process as needed
                }
            }
        }
    }

Tuesday, July 20, 2010

Using JSF Conversion with Custom Objects

My goal is to provide a user-facing input text box that accepts a comma-separated list of values, and converts these to an application-specific object. Since I'm using JSF, I'll take advantage of their built-in conversion facility - but I want to remain as decoupled from JSF as possible. This means I'll implement their Converter class, but I'll do so only with very minimal high-level business logic (as opposed to emulating their example usage in the JEE Tutorial example). That way, I can reuse my conversion logic in other frameworks, for other clients, etc.

My application object is a collection of name objects. The name objects look something like this:
public class MyName {   

    private String name;

    public MyName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean equals(Object obj) {
        if (null == obj) {
            return true;
        }

        if ((obj == null) || (getClass() != obj.getClass())) {
            return false;
        }

        MyName other = (MyName) obj;
        return new EqualsBuilder().append(this.name, other.name).isEquals();
    }

    public int hashCode() {
        return new HashCodeBuilder(3, 13).append(this.name).toHashCode();
    }

    public String toString() {
        return name;
    }
}
Note that I've implemented toString as well as the equals and hashCode methods. The builder classes are provided by Apache Commons Lang; I've blogged about them here.

The collection object uses the Java List to wrap the name objects:
public class MyNameList {

    private List<MyName> names = new ArrayList<MyName>();

    public MyNameList (List<MyName> names) {
        setNames(names);
    }

    public static MyNameList getInstance(String csv) {
        if (csv == null) {
            return new MyNameList();
        }
        String[] names = csv.split(",");
        List<MyName> nameList = new ArrayList();
        for (String name : names) {
            nameList.add(new MyName(name));
        }
        return new MyNameList(nameList );
    }

    public List<MyName> getNames() {
        return names;
    }

    public void setNames(List<MyName> names) {
        this.names = names;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer();
        String comma = "";
        for (MyName name: names) {
            sb.append(comma).append(name);
            comma = ",";
        }
        return sb.toString();
    }
}

Here's what the JSF converter implementation might look like - there's not much there, as planned:
public class MyNameListConverter implements Converter {

    public Object getAsObject(FacesContext context,
                              UIComponent component, String newValue)
            throws ConverterException {

        return MyNameList.getInstance(newValue);
    }

    public String getAsString(FacesContext context,
                              UIComponent component, Object value)
            throws ConverterException {

        return value == null? "" : value.toString();
    }
}
I must register the converter with JSF:
<converter>
    <description>
        Converter for CSV list of name values
    </description>
    <converter-id>MyNameListConverter</converter-id>
    <converter-class>
        com.mybiz.MyNameListConverter
    </converter-class>
</converter>
Finally I reference the converter in my JSF page:
 <ice:inputText id="nameValues" partialSubmit="true"
     converter="MyNameListConverter"
     value="#{bean.nameList}"/>

Lots of moving parts are needed when working with JSF. But, the more I can encapsulate, the less it will cost to migrate to a different web framework down the road.

Wednesday, June 23, 2010

Basic Embedded Jetty Setup: JSF 1.2 Webapp

Here are some basic code snippets I've used (to-date ... subject to change) to get an IceFaces-based (JSF 1.2) webapp deployed as an embedded Jetty webapp - using Maven for building. The artifacts include a configuration file, a minimal bootstrap class, the pom and the file used as the maven assembly-plugin descriptor.

The configuration file is jetty.xml, and doesn't require much. It lives under the ./etc directory of my project:

<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN" "http://jetty.mortbay.org/configure.dtd">

<Configure id="Server" class="org.mortbay.jetty.Server">

    <Set name="ThreadPool">
        <New class="org.mortbay.thread.QueuedThreadPool">
            <!-- initial threads set to 10 -->
            <Set name="minThreads">10</Set>
            <!-- the thread pool will grow only up to 200 -->
            <Set name="maxThreads">200</Set>
            <!-- indicates that having 20 and below, the pool will be considered low on threads -->
            <Set name="lowThreads">20</Set>
            <!-- The number of queued jobs (or idle threads) needed before the thread pool is grown (or shrunk) -->
            <Set name="SpawnOrShrinkAt">2</Set>
        </New>
    </Set>

    <Call name="addConnector">
        <Arg>
            <New class="org.mortbay.jetty.nio.SelectChannelConnector">
                <!-- the ip address or domain to bind -->
                <Set name="host">
                    <SystemProperty name="jetty.host"/>
                </Set>
                <!-- the port to use/bind, defaults to 8080 if property not set -->
                <Set name="port">
                    <SystemProperty name="jetty.port" default="8080"/>
                </Set>
                <!-- the time in milliseconds when a connection is considered idle -->
                <Set name="maxIdleTime">300000</Set>
                <!-- the number of acceptors (their job is to accept the connection and dispatch to thread pool) -->
                <Set name="Acceptors">2</Set>
                <!-- should the connection statistics be turned on? (Not advisable in production) -->
                <Set name="statsOn">false</Set>
                <!-- the confidential port -->
                <Set name="confidentialPort">8443</Set>
                <!-- indicates the minimum number of connections when the server is considered low on resources -->
                <Set name="lowResourcesConnections">5000</Set>
                <!-- when low on resources, this indicates the maximum time a connection must be idle to not be closed -->
                <Set name="lowResourcesMaxIdleTime">5000</Set>
            </New>
        </Arg>
    </Call>

    <!-- Stops the server when ctrl+c is pressed (registers to Runtime.addShutdownHook) -->
    <Set name="stopAtShutdown">true</Set>
    <!-- send the server version in the response header? -->
    <Set name="sendServerVersion">true</Set>
    <!-- send the date header in the response header? -->
    <Set name="sendDateHeader">true</Set>
    <!-- allows requests(prior to shutdown) to finish gracefully -->
    <Set name="gracefulShutdown">1000</Set>

</Configure>

This configuration file is referenced by the bootstrap class, using it to configure Jetty. This class also sets the context for the webapp, points to the top-level directory of the exploded WAR content, sets a webapp context and a default context as handlers for Jetty, and starts up the webserver:

public class MyJettyWebServer {

    public static void main(String[] args) throws Exception {

        Server jetty = new Server();

        // configure Jetty by pointing to config file(s)
        String[] configFiles = { "etc/jetty.xml" };
        for (String configFile : configFiles) {
            XmlConfiguration configuration = new XmlConfiguration(new File(configFile).toURI().toURL());
            configuration.configure(jetty);
        }

        // set the context for the webapp
        WebAppContext appContext = new WebAppContext();
        appContext.setContextPath("/mycontext");

        // point to the top-level directory of the exploded WAR content
        File warPath = new File(System.getProperty("basedir"));
        appContext.setWar(warPath.getAbsolutePath());

        // set a webapp context and a default context as handlers for Jetty
        HandlerList handlers = new HandlerList();
        handlers.setHandlers(new Handler[]{ appContext, new DefaultHandler() });
        jetty.setHandler(handlers);

        // start up the webserver
        jetty.start();
    }
}


The pom specifies IceFaces 1.8.2, being careful to exclude the EL API jar wherever that's brought in transitively, as per http://www.icefaces.org/docs/v1_8_0/htmlguide/devguide/appendixA.html; and it specifies Jetty and Log4J artifacts. Note that JSP support is explicitly specified:

    ....
    <!-- use JAR packaging for embedded Jetty -->
    <packaging>jar</packaging>
    ....
    <dependencies>
        <dependency>
        <dependency>
            <groupId>org.icefaces</groupId>
            <artifactId>icefaces</artifactId>
            <version>1.8.2</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.el</groupId>
                    <artifactId>el-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.icefaces</groupId>
            <artifactId>icefaces-comps</artifactId>
            <version>1.8.2</version>
        </dependency>
        <dependency>
            <groupId>org.icefaces</groupId>
            <artifactId>icefaces-facelets</artifactId>
            <version>1.8.2</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.el</groupId>
                    <artifactId>el-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>1.2_12</version>
        </dependency>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>1.2_12</version>
        </dependency>
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jetty</artifactId>
            <version>6.1.21</version>
        </dependency>
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jetty-util</artifactId>
            <version>6.1.21</version>
        </dependency>
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jsp-2.1-jetty</artifactId>
            <version>6.1.21</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4jVersion}</version>
        </dependency>
    </dependencies>
</project>

The assembly-plugin descriptor has a few things worth mentioning. In the dependency sets, I lay down my dependencies in the standard webapp location, ./WEB-INF/lib:

        <dependencySet>
            <unpack>false</unpack>
            <scope>runtime</scope>
            <outputDirectory>war/WEB-INF/lib</outputDirectory>
        </dependencySet>

I also specify several destinations for my dev-time files to deal with Jetty-related stuff:

        <!--
        Jetty deployment: configuration file location
        -->
        <fileSet>
            <directory>etc</directory>
            <outputDirectory>/usr/local/mywebapp/etc</outputDirectory>
            <fileMode>0644</fileMode>
        </fileSet>
        <!--
        Jetty deployment: webapp deployment location - hmmm, this one might not be needed...
        -->
        <fileSet>
            <directory>webapps</directory>
            <outputDirectory>/usr/local/mywebapp/webapps</outputDirectory>
            <fileMode>0644</fileMode>
        </fileSet>
        <!--
        Jetty deployment: production-time exploded warfile location
        -->
        <fileSet>
            <directory>src/main/webapp</directory>
            <outputDirectory>/usr/local/mywebapp/war</outputDirectory>
            <fileMode>0644</fileMode>
        </fileSet>

Finally, to start the program:

java -server -Dbasedir=/usr/local/mywebapp/war -cp /usr/local/mywebapp/war/WEB-INF/lib/* com.mybiz.MyJettyWebServer

Browse to localhost:8080 and your webapp should appear.

You'll notice I did not use the maven-jetty plugin (nor the jetty-maven plugin - yes, there are two different ones, each with different names, schemas and behaviors). The good news about the plugin is that it shields you from much of the configuration/deployment exercises you'll need; that's also the bad news. I needed to understand explicitly what dependencies, etc. I'd need for production, so I chose to do things manually. The good news around this is that I've done most of the heavy lifting to grease the skids for future embedded-Jetty exercises.

References

Jetty 6.x Wiki
Jetty 7x, 8.x Wiki

Tuesday, June 22, 2010

Ternary Expressions Problem with JSF 1.2

This is a followup on my previous post that offered a workaround to this error message, as seen when working with JSF 1.2:

javax.el.ELException: Error Parsing: 
Caused by: com.sun.el.parser.ParseException: Encountered ":text"

In my first post, I failed to find the root cause, so I took the path of least resistance in the interest of the project schedule (using the heavy-handed approach of two separate panel groups, backing the condition out to the "rendered" attribute of each group). As it turns out, the root cause is lack of white space around the colon, as explained in this article from Oracle. That is, given an expression:

#{isThisTrue?doThis:doThat}

...and depending on what the deployment environment is, you'll either notice nothing or bump into this error message. When that first post was written, I was deploying to Glassfish 8.x - and I needed to use the workaround described above. Recently, I deployed to JBoss 4.x and later to 5.1, and here I did not notice anything - but then I redeployed to embedded Jetty 6.1.x, and the problem re-appeared. This is probably because JBoss shielded me from needing the magic combination of JSF, JSP, Facelets, JSTL and etc. to make things work, but vanilla Jetty does not.

In either event, you might have better luck than I with determining the dependency mix, including tweaking the web.xml to configure the correct expression factory, trying various permutations of Jetty's JSP libraries, and etc. (aka "time sink"); but, more simply, the fix is to change the problematic expression (well, actually it's a bug in JSF 1.2) to this:

#{isThisTrue?doThis : doThat}

This time, I googled for the right thing ("JSF 1.2 ternary parse exception") and, by now, the article from Oracle had finally been published (it wasn't there until after I originally bailed out with my workaround).

Monday, March 15, 2010

Case Study: Add Functionality Without Changes to Code

What I'll describe here is an exercise I've completed that adds functionality to an existing codebase without changing that codebase. The product is not dynamically "pluggable", service-oriented, etc., so I don't have those levers to address the problem; instead, I've used Aspect Oriented Programming (AOP), JSF phase listeners, and the Observer design pattern to add to the codebase in a modular way. This gives me an easy way to remove that code if that's called for - and, for this exercise, that's the primary goal.


Our team's product cycle is transitioning with one release in test cycle, moving soon to a Beta audience; and with some new functionality targeted for the next release. These releases are being managed in separate SCM trees; however, due to various infrastructure limitations, we're being asked to wait on checking in changes to the test-cycle branch. But I don't want this to stop me from moving forward on that release.

There are various well-known problems, of course, if one makes "too many" changes to a  codebase before checking things in:
  1. There could be a conflict-resolution exercise between my changes and my teammates' changes to the same files.
  2. If a bug is found in Beta, that code will need a bugfix and a patch - but if I've intermingled new stuff in the code needing bugfixes, I have a potentially error-prone, tedious and time-consuming version control exercise.
There are SCM strategies to address #2; but for the sake of argument, let's just say that my constraint is to develop the new functionality with minimal - if not zero - impact to existing code, to avoid both potential problems from above.

For that matter, I wanted to challenge myself to see just how much I could do with this type of constraint - so I gave myself some "rules":
  1. keep the code changes as modular as possible so they can easily be added, for that matter easily removed if called for;
  2. ideally, no changes at all are made to existing code;
  3. if for some reason, I must change existing code, it must be done in such a way that new classes, declarations, etc. can be introduced, but existing code must not make reference to the new artifacts
So, e.g., I can use aspects, includable XML files, listeners of various flavors, and the like. Looking more closely at my "rules", it appears that #2 and #3 actually are the "how-to" supporting the "what" of #1 - i.e., the true goal here is to make it easy to add or remove the functionality if called for.

Here's the new functionality to be added:
  1. At various points during the customer's use of the product, a certain process should be launched to accomplish a particular goal. I'm intentionally being vague since the details don't really matter here.
  2. For each version of the product, that process should be executed just once without any confirmation from the user that it should proceed; but once it's been executed that first time (for a particular product release), the user should be issued some kind of popup confirmation dialog (this is a webapp UI) that offers a choice: allow the process to proceed with due caution, or just bail out.
  3. Every time a new product release is installed, the warning mechanism resets, i.e. the very next time the user launches the process, no such confirmation dialog appears.
The relevant pieces of the technology stack that I'll be "modifying" includes:
  1. A JSF-based web tier, using in particular the IceFaces component set;
  2. Spring 3.0
Breaking things down, it seems I'll need to do things like this:
  1. Persist some information around the product version, to be generated at build time and deployed with product installation;
  2. intercept the rendering of the UI button that launches the process so that the confirmation dialog can be associated with it, such that when the button is clicked, the confirmation will appear (giving the user a choice of proceeding or not) - but the confirmation appears only if the process has already executed for this product release;
  3. persist information after each process execution indicating this execution has occurred for a given product installations; and
  4. interpret the lack of that persisted information to indicate the process has not executed for this installation. This will be the initial condition, and the condition after each new product release is installed.

What I did to address #1 is trivial, and frankly out of scope for the purposes of this post. Likewise, #4 is reasonably straightforward; no additional details are needed around this.

To address #2 - intercept the rendering of the user action - my initial instinct tells me this sounds like an aspect...well, to be honest, I was looking for some excuses to use aspects - not only because I think this is a good approach to adding functionality in a modular way, but because I want to get better at AOP. A solution for #3 might also use an aspect, so that after the process has been run, the process-execution-history is updated.

As it turned out, the most interesting problem was intercepting the rendering of the UI button to attach a confirmation dialog dynamically. Note that sometimes the confirmation should be there - if the process has already been run - and sometimes, the process should just get launched without any warning to the user.

Let's first establish the confirmation dialog to be used. I'm using IceFaces, which provides a panelConfirmation tag that I use like this:

    <!--
    Warn user if process has already executed for this release
    -->
    <ice:panelConfirmation 
       id="warnProcessExecuted" 
       message="#{msgs['confirm.rerun']}"
       acceptLabel="Yes" cancelLabel="No"/>

The straightforward way to use this is to simply add it as an attribute to the existing IceFaces button that launches the process:

<ice:commandButton id="launchProcess"
     value="Launch Process"
     immediate="true"
     confirmationPanel="warnProcessExecuted"
     actionListener="#{eventsManager.startProcess}"/>

But this violates my self-imposed constraint described by rule #2 above: "ideally, no changes at all are made to existing code".  So my initial thought is to do this:
  1. intercept the handling of the action after user clicks on the button;
  2. find the JSF component associated with the button; and
  3. dynamically add the confirmationPanel attribute to that button component.
Doing things this way also would factor out the conditional part: if the process has not executed yet, there's no need to add the confirmation. But it turns out that trying to add the attribute during the action handling is too late - what I want is to intercept the rendering of the button. This sounds like I could use a JSF phase listener that listens for the beginning of the RENDER_RESPONSE phase to do this. This worked out just fine, but the thing about it that bothered me was that this happens several times for each action, and the method that I use to attach the attribute gets called each time. In this case, no harm is done; but I'd like to find a more general solution so my code execution is more deterministic and less at the mercy of the JSF lifecycle - bottom line, so that the method of interest is called only once at the beginning of the RENDER_RESPONSE phase. Here's how I did it:

First I create a reusable hierarchy of JSF phase listeners. The superclass provides the PhaseListener implementation, and additionally provides a registration mechanism - with which it remembers any interested listeners for a given phase. Each registered listener implements a PhaseObserver interface, and is notified at the beginning and end of each JSF phase:

public class PhaseMonitor implements PhaseListener {

    private static Map<JsfPhaseId, Set<PhaseObserver>> observers =
        new HashMap<JsfPhaseId, Set<PhaseObserver>>();

    // notify all registered observers for this phase that the phase has begun
    public void beforePhase(PhaseEvent event) {

        JsfPhaseId phaseId = JsfPhaseId.getJsfPhaseId(event.getPhaseId());
        Set<PhaseObserver> these = observers.get(phaseId);
        if (these != null) {
            for (PhaseObserver observer : these) {
                observer.notifyBeforePhase(phaseId);
            }
        }
    }

    // notify all registered observers for this phase that the phase has ended
    public void afterPhase(PhaseEvent event) {

        JsfPhaseId phaseId = JsfPhaseId.getJsfPhaseId(event.getPhaseId());
        Set<PhaseObserver> these = observers.get(phaseId);
        if (these != null) {
            for (PhaseObserver observer : these) {
                observer.notifyAfterPhase(phaseId);
            }
        }
    }

    // observer pattern: interested observers implement the PhaseObserver interface and register their interest
    public static void register(JsfPhaseId phase, PhaseObserver observer) {

        Set<PhaseObserver> these = observers.get(phase);
        if (these == null) {
            these = new HashSet<PhaseObserver>();
        }
        these.add(observer);
        observers.put(phase, these);
    }

    protected PhaseId getMyPhaseId() { // subclasses will override this for each JSF phase
        return null;
    }

    public PhaseId getPhaseId() {
        return getMyPhaseId();
    }
}


The JsfPhaseId is a first-class enum, provided not only so the observers can reference a simple enum constant (which the JSF PhaseID does not provide - it is not an enum (!!)), but so that client code need not be tightly coupled to JSF. Granted, clients will use the JsfPhaseId, which uses JSF, so the deployment will be coupled to JSF - but at least I've encapsulated my usage of JSF by providing this facade:

public enum JsfPhaseId
{
    APPLY_REQUEST_VALUES, INVOKE_APPLICATION, PROCESS_VALIDATIONS,
    RENDER_RESPONSE, UPDATE_MODEL_VALUES, RESTORE_VIEW, UNKNOWN;

    public static JsfPhaseId getJsfPhaseId(PhaseId phaseId) {

        if (phaseId.equals(PhaseId.APPLY_REQUEST_VALUES)) {
            return JsfPhaseId.APPLY_REQUEST_VALUES;
        } else if (phaseId.equals(PhaseId.INVOKE_APPLICATION))  {
            return JsfPhaseId.INVOKE_APPLICATION;
        } else if (phaseId.equals(PhaseId.PROCESS_VALIDATIONS)) {
            return JsfPhaseId.PROCESS_VALIDATIONS;
        } else if (phaseId.equals(PhaseId.RENDER_RESPONSE)) {
            return JsfPhaseId.RENDER_RESPONSE;
        } else if (phaseId.equals(PhaseId.UPDATE_MODEL_VALUES)) {
            return JsfPhaseId.UPDATE_MODEL_VALUES;
        } else if (phaseId.equals(PhaseId.RESTORE_VIEW)) {
            return JsfPhaseId.RESTORE_VIEW;
        }
        return JsfPhaseId.UNKNOWN;
    }
}

Each phase-specific subclass of PhaseMonitor does this:

public class RenderResponsePhaseMonitor extends PhaseMonitor {

    private PhaseId phaseId = PhaseId.RENDER_RESPONSE;
    protected PhaseId getMyPhaseId() {
        return phaseId;
    }
}

This is repeated for the other JSF phases. Now I need to add these phase listeners to the code, but in a way that minimizes impact that existing code. So, I do not want to modify my existing JSF configuration file by declaring these listeners; instead, I add a new config file using the web-tier deployment descriptor (web.xml):

<context-param>
        <param-name>javax.faces.CONFIG_FILES</param-name>
        <param-value>/WEB-INF/faces-config-application.xml, /WEB-INF/faces-config-listeners.xml</param-value>
</context-param>

That config file looks like this:

<faces-config xmlns="http://java.sun.com/JSF/Configuration">
    <!-- listen for phase events to facilitate phase listening, notification -->
    <lifecycle>
        <phase-listener>com.mybiz.web.jsf.lifecycle.ApplyRequestValuesPhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.InvokeApplicationPhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.ProcessValidationsPhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.RenderResponsePhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.RestoreViewPhaseMonitor</phase-listener>
        <phase-listener>com.mybiz.web.jsf.lifecycle.UpdateModelValuesPhaseMonitor</phase-listener>
    </lifecycle>
</faces-config>

The interested observers implement this interface:

public interface PhaseObserver {

    public void notifyBeforePhase(JsfPhaseId phaseId);
    public void notifyAfterPhase(JsfPhaseId phaseId);
}

With these levers in place, I can now implement an observer that will be notified once and only once at the beginning of the RENDER_RESPONSE phase, at which time it will determine if a confirmation for the user is needed; if so, it will find the JSF component of interest and attach the confirmation panel, and, if the user elects to proceed, updating some persistent history "somewhere" with information about this execution; else it sets the attribute value for the confirmation panel to an empty string so that no such dialog pops up. Since I don't want to minimize my changes to existing code, I add this functionality with an aspect:

@Aspect
public class ExecutionAspects implements PhaseObserver {

    public ExecutionAspects() {
        PhaseMonitor.register(JsfPhaseId.RENDER_RESPONSE, this);
    }

    private ExecutionHelper executionHelper;  // injected via Spring
    public void setExecutionHelper(ExecutionHelper theHelper) {
        executionHelper = theHelper;
    }

    /**
     * Establish a pointcut that describes a method which we know will be called when the button is rendered
     */
    @Pointcut("execution(* com.mybiz.view.ViewHelper.isLaunchProcessButtonShowing(..))")
    public void isLaunchProcessButtonShowing() {
    }

    // here's how we enforce the "once and only once" constraint:
    private boolean needConfirmationForThisRequest = true;
    public void notifyBeforePhase(JsfPhaseId phaseid) {
        needConfirmationForThisRequest = true;
    }
    public void notifyAfterPhase(JsfPhaseId phaseid)
    {
        needConfirmationForThisRequest = false;
    }

    /**
     * Intercept rendering of button to detect whether or not the process has already been run for this release
     */
    @Around("isLaunchProcessButtonShowing()")
    private boolean interceptRender(ProceedingJoinPoint pjp) throws Throwable {
        if (needConfirmationForThisRequest)
        {
            // get UI component, add confirmation panel if needed
            HtmlCommandButton button =
                    (HtmlCommandButton) FacesUtils.findComponent(FacesUtils.getFacesContext().getViewRoot(),
                            "launchProcess");  // search from root of JSF component tree for the launch button ID
            if (executionHelper.getProcessHasExecutedForThisProduct()) {
                // attach the confirmation
                button.setPanelConfirmation("warnProcessExecuted");
            } else {
                // set the confirmation attribute to an empty string so no warning will appear
                button.setPanelConfirmation("");
            }
            needConfirmationForThisRequest = false;
        }
        // return value as normal
        return (Boolean)pjp.proceed();
    }

    /**
     * Establish a pointcut that intercepts the user action of launching the process
     */
    @Pointcut("execution(* com.mybiz.view.EventsHelper.startProcess(..))")
    public void startProcess()
    {
    }

    /**
     * Intercept launching of process to facilitate updating the execution history after it's done
     */
    @Around("startProcess()")
    private void interceptProcess(ProceedingJoinPoint pjp) throws Throwable
    {
        pjp.proceed();
        // update history so user can be warned that it's already been run (next time it's requested)
        executionHelper.updateConfMergeHistory();
    }
}

Now the aspect needs to be added to runtime execution; I already have a Spring context file for the existing product functionality, but again I don't want to change that file. Instead, I modify the web-tier deployment descriptor to add a new one:

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/beans-all.xml, /WEB-INF/beans-execution.xml</param-value>
</context-param>

That Spring context file manages the ExecutionAspects class, supplying the ExecutionHelper dependency:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
       ">

    <!--
    Configuration file used to maintain execution information - i.e. as a control for when the process
    is run with or without warning, we need to maintain information about what release is this
    product, and compare that to what release was the last execution run against.
    -->
    <bean id="executionHelper" scope="session" class="com.mybiz.aspects.ExecutionHelper">
    </bean>

    <aop:aspectj-autoproxy proxy-target-class="false"/>

    <bean id="execution-aspect" class="com.mybiz.aspects.ExecutionAspects">
        <property name="executionHelper" ref="executionHelper"/>
    </bean>

</beans>

The ExecutionHelper is of minimal interest here; it simply does CRUD on "some persistence mechanism" to manage information about what is the current product release and what particular release has the process last been executed against. It provides a convenience method (getProcessHasExecutedForThisProduct(), as seen above) encapsulating all of that information with a boolean indicating exactly what it's name suggests.


So let's revisit my initial goals and see how well I've done:
  1. keep the code changes as modular as possible so they can easily be removed if called for;
  2. ideally, no changes at all are made to existing code;
  3. if for some reason, I must change existing code, it must be done in such a way that new classes, declarations, etc. can be introduced, but existing code must not make reference to the new artifacts (this facilitates rule #1)
#1: are my changes modular? In the sense that they can be removed very easily if needed, yes - here's what I'd need to do to remove this functionality: change this -->

<param-value>/WEB-INF/beans-all.xml, /WEB-INF/beans-execution.xml</param-value>

to this -->

<param-value>/WEB-INF/beans-all.xml</param-value>nclude src="/WEB-INF/includes/panel-confirmation.jspx"/>

Without the single additional declaration of Spring context that attaches the new aspect to the runtime, the aspect will not get instantiated, let alone executed. All of the existing code - well, most of it anyway - remains untouched. The new code can be left as an addition to the codebase, ready for activation whenever product management calls for that.

You'll notice I said most of the existing code is unchanged. Beyond the addition of the 2nd Spring context, as noted here, and the additional JSF Config file that declares the hierarchy of phase listeners, I did need to make one change to the JSF file that declares the command button; I needed to include the new JSF file that declares the confirmation within the same form. Apparently this is a constraint of the component set, and it is not surprising. So I ended up doing this:


<ice:commandButton id="launchProcess"
    value="Launch Process"
     immediate="true"
    actionListener="#{eventsManager.startProcess}"/>
             
 <!-- confirmation panel must be in same form as the button that references it. The
  "launchProcess" button, above, is managed dynamically to point to this confirmation
  in an aspect. For better modularity, include the panelConfirmation snippet:
  -->
  <ui:include src="/WEB-INF/includes/panel-confirmation.jspx"/>

So I didn't quite succeed with rule #2 -- I did have to make some changes to existing code. But for all intents and purposes, it's not an issue -- since the change to the code is a declaration that is not referenced by existing code. I'd argue likewise for the addition of the JSF Config file with the hierarchy of phase listeners and built-in observer mechanism - this is, in my opinion, a worthwhile addition to any JSF application, one that I'll likely continue doing from this point forward. I just happened to leverage it with an aspect that registers as an interested observer of the RENDER_RESPONSE phase. That is the essence of modularity.

Again, not quite successful with rule #3 - since the changes to the web.xml do make reference to the new JSF Config and Spring context files. But again, in spirit that goal was only in place to facilitate success on rule #1 - and bottom line, I can add or remove this new functionality without breaking a sweat.

Monday, June 8, 2009

Netbeans 6.7 + JBoss 5.1 Library Dependencies

Moving my IDE from NetBeans 6.1 to 6.7.1 (not a GA, but the nightly build 200906051401) resulted in failure in my web application compilation. I had pointed NetBeans to the same JBoss 5.1 installation as I used in NB 6.1, and associated my web app project with that server, so this "should" have worked, but did not. I don't have the time to analyze exactly why, so I won't discuss that; instead, I'll just provide the solution:
  1. Create a NetBeans library (named e.g. JBoss-5.1-Common) that points to all jarfiles under $JBOSS_HOME/common/lib, and add that to your project. Make sure to uncheck the Package checkbox for that library or it'll be added to your deployed warfile, which could result in classloading problems
  2. Add the JSF 1.2 library that comes out of the box with NetBeans - again, uncheck the Package option for the same reason.
This should address compile-time issues, or more accurately I should say "it worked for me".


Friday, May 29, 2009

Tip: Use Facelets 1.1.15 in JBoss 5.x

I've begun my research into RichFaces, and decided to actually read their developer guide instead of just winging it. Sometimes I do crazy things, I know. Anyway, one of their initial suggestions was to get a plain JSF application in place and working, and I thought this was a decent starting point - that way, any anomalies could be more easily traced as I added RichFaces stuff.

So I put a plain vanilla Facelets-JSF app together (i.e., one that doesn't use a third-party component set, like IceFaces or RichFaces) , and got it working just fine on JBoss 4.2.2 (here I'm using Facelets 1.1.14). However, with my migration to JBoss 5.1, this rather dumb prototype stopped working, with this exception on initial deployment of the webapp:

SEVERE [compiler] Missing Built-in Tag Libraries! Make sure they are included within the META-INF directory of Facelets' Jar
15:35:25,318 SEVERE [viewhandler] Error Rendering View[/index.xhtml]
java.lang.NullPointerException
at com.sun.facelets.compiler.NamespaceHandler.apply(NamespaceHandler.java:49)
at com.sun.facelets.compiler.EncodingHandler.apply(EncodingHandler.java:25)
at com.sun.facelets.impl.DefaultFacelet.apply(DefaultFacelet.java:95)
at com.sun.facelets.FaceletViewHandler.buildView(FaceletViewHandler.java:524)
.............

On subsequent page loads, the "Missing Built-in Tag Libraries" message stopped appearing, but the NPE on NamespaceHandler continued to happen. Googling on the NPE was not entirely fruitful, but searching against the tag libraries problem led me to various known solutions; I addressed it by using the 1.1.15 version of Facelets.

For decent guidance on constructing a simple Facelets web app, here's a nice Facelets tutorial.

Thursday, May 28, 2009

Netbeans + JBoss 4.2/5.x + IceFaces + Facelets: Gotcha

On creating a new WebApp project in NetBeans 6.x, I noticed a number of frameworks offered that support various technologies. Since I was prototyping a JSF-Facelets app, I chose the Facelets framework; as a result, NetBeans added the jsf-facelets.jar to my project libraries (which means these jars would be deployed as part of the warfile). I'll now file that decision in the "seemed like a good idea at the time" category: NetBeans users, here's a heads-up; please read on.

My goal was to compare RichFaces and IceFaces component sets (about which I'll post my findings later). Starting with IceFaces 1.8, I added dependencies as their documentation guided me for the JBoss 5.x app server - including the icefaces-facelets.jar, which I assumed was their own icefaces-specific layer above the standard Facelets distro. As it turns out, not so much.

On putting together a simple JSF page with Facelets tags, the page load yielded this exception:

java.lang.NullPointerException
com.icesoft.faces.facelets.D2DFaceletViewHandler.renderResponse(D2DFaceletViewHandler.java:268)
com.icesoft.faces.application.D2DViewHandler.renderView(D2DViewHandler.java:153)
com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:110)

........

This seemed to point to a problem between IceFaces and Facelets, so my first instinct was to think that JBoss 5.x already had the Facelets classes loaded, and I was confusing things by adding my own version of these. As it turned out, I was on the right track...but more blind leads were to follow: in trying to reload the page, I got this exception:
java.lang.IllegalStateException: BaseClassLoader@144e022{vfsfile:}
classLoader is not connected to a domain (probably undeployed?) for class
javax.servlet.jsp.SkipPageException
This made me think that the removal of the Facelets jar was a mistake. Actually, no it was not; my mistake was trying to reload the page too quickly after redeploying. JBoss 5.0 takes a bit longer to complete a redeployment than I expected; had I simply waited another 5-10 seconds before reloading the page, I would have seen my original NPE problem solved instead of thinking I'd traded it for a different one.

What made this more confusing was that I tried the same webapp in JBoss 4.2, and had no problem at all. The IceFaces documentation around dependencies for JBoss 4.x vs 5.x is exactly the same; so it was mysterious why the webapp would work OK in 4.2 but not in 5.x.

After a bit more experimentation, I stumbled on the answers to all of the above:
  1. The standard Facelets jar should not be deployed when icefaces-facelets.jar is deployed; the latter appears to be an IceFaces-specific adaptation of the standard. This means NetBeans users should not choose the Facelets framework for a new WebApp project if they are going to be using Facelets with IceFaces.
  2. JBoss 4.2 classloading masks this issue by (apparently) loading the IceFaces version of these classes instead of the standard version, so things worked out just fine with 4.2.
  3. JBoss 5.0 loads the standard version of Facelets classes first (apparently), hence the problem.
  4. JBoss 5.0 redeployment of webapps takes a bit longer than you'd expect - in fact I noticed the TomcatDeployment mechanism undeploying/deploying my webapp three times before it finally stabilized, at which point page reloads will succeed without the misleading IllegalStateException.
  5. JBoss 5.1 redeployment goes by much faster; TomcatDeployment undeploys my webapp only once.

Wednesday, May 13, 2009

JSF Cheatsheet

Here's a collection of various idioms, patterns, tips, and etc. around JSF 1.2. It's a work in progress that I'll be adding to over time. So far, it's compiled by pulling stuff from the following websites - and I thank each of the authors for my reproduction of their content here:

Preso by Ed Burns:
https://javaserverfaces.dev.java.net/presentations/demystifyingjsf.pdf

Tutorial from IBM (requires registration but is worth the hassle):
https://www6.software.ibm.com/developerworks/education/j-jsf1/section7.html

JSF Anti-Patterns and Pitfalls
http://www.theserverside.com/tt/knowledgecenter-is/knowledgecenter-is.tss?l=JSFAnti-PatternsandPitfalls

Java EE 5 Tutorial
http://java.sun.com/javaee/5/docs/tutorial/doc/bnaph.html

Declare Faces Servlet in web.xml:
<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 Servlet</servlet-name>
  <url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>/faces/*</url-pattern>
</servlet-mapping>

JSF Configuration File

If you name your Faces configuration file faces-config.xml and place it in your Web application's WEB-INF directory, then the Faces Servlet picks it up and uses it automatically (because it's the default). Alternatively, you can load one or more application-configuration files through an initialization parameter — javax.faces.application.CONFIG_FILES — in your web.xml file with a comma-separated list of files as the body. You will likely use the second approach for all but the simplest JSF applications (but be sure to not list faces-config.xml in that initialization parameter, or any registered phase listeners will fire twice).

Sample JSF config file:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config 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-facesconfig_1_2.xsd"
version="1.2">
  <managed-bean>
    <managed-bean-name>myBean</managed-bean-name>
    <managed-bean-class>com.mydomain.MyBean</managed-bean-class>
    <managed-bean-scope>request</managed-bean-scope>
  </managed-bean>
</faces-config>
JSF configuration files are specified via the javax.faces.CONFIG_FILES context parameter in web.xml:

<context-param>
  <description>comma separated list of JSF conf files</description>
  <param-name>javax.faces.CONFIG_FILES</param-name>
  <param-value>
    /WEB-INF/menu-config.xml,
    /WEB-INF/services-config.xml
  </param-value>
</context-param>
Again: do not specify faces-config.xml in this context-param -- if you do, any registered phases listeners will fire twice.


Declare standard JSF tags:

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
The html taglib contains all the tags for dealing with forms and other HTML-specific items. The core taglib contains all the logic, validation, controller, and other tags specific to JSF.

An <h:panelGrid> can contain only components, whereas <h:form>, <f:view> and <h:panelgroup> can contain both HTML and components.

Import stylesheets:

<head>
  <title>My Application</title>
  <link rel="stylesheet" type="text/css"
    href="<%=request.getContextPath()%>/css/styles.css" />
</head>

User-Facing Messages

Customize messages (this approach does not scale, since it must be repeated for each section needing it):

<%-- case by case basis; message appears immediately to right of field --%>
<h:outputLabel value="Zip Code" for="zipcode" />
<h:inputText id="zipcode" label="Zip Code"
  value="#{myBean.zipcode}" required="true"
  requiredMessage="required" converterMessage="not a valid zip code"/>
<h:message for="zipcode" />
Change messages globally (this scales well, can be overridden as needed using case-by-case approach):

  • Add this tag to beginning of JSF config file(s):
<application>
  <message-bundle>mymessages</message-bundle>
</application>
  • Add entries to mymessages.properties resource bundle:
javax.faces.component.UIInput.REQUIRED_detail=value is required
javax.faces.converter.IntegerConverter.INTEGER_detail=that's not a valid integer
The complete list of default messages are found in the JSF 1.2 RI jarfile jsf-impl.jar, under javax.faces.Messages.properties.

In case the standard error messages don’t meet your needs, create new ones in resource bundles and configure the resource bundles in your application configuration resource file. For example, this message is stored in the resource bundle, MyMessages.properties:

invalidZipCode=The value you entered is not a zip code.

The resource bundle is configured in the application configuration file:

<application>
  <resource-bundle>
    <base-name>com.mydomain.MyMessages</base-name>
    <var>msgs</var>
  </resource-bundle>
</application>
The base-name element indicates the fully-qualified name of the resource bundle. The var element indicates the name by which page authors refer to the resource bundle with the expression language:

<h:inputText id="zipcode" label="Zip Code"
  value="#{myBean.zipcode}" converterMessage="#{msgs.invalidZipCode}">
...
</h:inputText>
Add messages to be displayed based on outcomes in server-side processing:

<h:messages infoClass="infoClass" errorClass="errorClass"
  layout="table" globalOnly="true"/>
....
<h:inputText id="minimum" label="Minimum"
  value="#{myBean.modelObject.minimum}" required="true"
  binding="#{myBean.minimum}" />
<h:message for="minimum" errorClass="errorClass"/>
....

acesContext facesContext = FacesContext.getCurrentInstance();
try {
...
  facesContext.addMessage(null, new FacesMessage(
    FacesMessage.SEVERITY_INFO, "Completed successfully", null));
...
} catch (Exception ex) {
  facesContext.addMessage(null,
    new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.getMessage(), null));
...
} 

Adjust styles dynamically

<h:outputLabel value="Minimum" for="minimum"
  styleClass="#{myBean.minimumStyleClass}"/>
......
public String getMinimumStyleClass() {
  if (minimum.isValid()) {
    return "labelClass";
  } else {
    return "errorClass";
  }
} 

Access Component from Java

Factor out logic from JSP into managed bean (bind component to managed bean; lets you manipulate the component's state programatically without traversing the component tree to get to the component):

<h:panelGroup binding="#{myBean.panel}" rendered="false">
.......
private UIPanel panel;
public UIPanel getPanel() {
  return panel;
}

public void setPanel(UIPanel panel) {
  this.panel = panel;
}

public String execute() {
...
  try {
    modelObject.doSomething();
    panel.setRendered(true);
...
  } catch (Exception ex) {
...
    panel.setRendered(false);
  }
  return null;
} 

Injection into managed beans:

Using standard JSF Inversion of Control configuration:

<managed-bean>
  <managed-bean-name>myBean</managed-bean-name>
  <managed-bean-class>
    com.myDomain.MyBean
  </managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
  <managed-property>
    <property-name>modelObject</property-name>
    <value>#{modelObject}</value>
  </managed-property>
</managed-bean>
<managed-bean>
  <managed-bean-name>modelObject</managed-bean-name>
  <managed-bean-class>
    com.myDomain.MyModel
  </managed-bean-class>
  <managed-bean-scope>none</managed-bean-scope>
</managed-bean>
If you need to explicitly manage the order in which properties are set:

  • The specification states that a JSF implementation must inject the dependencies of a managed bean in the order in which they are configured
  • Applications that are using JSF 1.2 can take advantage of the PostConstruct annotation. Below, the PostConstruct annotation instructs the JSF implementation to invoke the initialize method after the managed bean has been created.
private ModelAttrs min, max; // injected
    // no setters and getters for min, max
  @javax.annotation.PostConstruct
  public void initialize() {
    if(min == null || max == null) {
      throw new NullPointerException("init failed - min or max is null");
    }
    if(min > max)) {
      throw new IllegalStateException("min cannot be larger than max");
    }
  }
However, it's still possible to call the no-arg constructor from somewhere other than the JSF framework, so this is not bulletproof.


  • Use a full blown dependency injection framework. Using Spring is as easy as placing the following lines of code in your JSF deployment descriptor.
<application>
  <variable-resolver>
    org.springframework.web.jsf.DelegatingVariableResolver
  </variable-resolver>
</application>
A JSF implementation is not required to warn you about misspelled class names or cyclical references in managed bean declarations at startup, but both will result in a runtime exception. JSF 1.2 will warn you about duplicate managed bean declarations but 1.1 will not.

Use JSFUnit to help address these types of problems (although I've yet to try it, so I'm unclear about the status of JSFUnit static analysis features, but it appears that the runtime testing is GA). You can also avoid some of these problems with annotations libraries found in Seam or Shale.




Navigation

Navigate via comandLink and navigation rule -from *any* view - URL in browser doesn't change (can't bookmark):

<navigation-rule>
  <from-view-id>*</from-view-id>
  <navigation-case>
    <from-outcome>services</from-outcome>
    <to-view-id>/pages/services.jsp</to-view-id>
  </navigation-case>
</navigation-rule>
...
<h:commandLink action="services" value="Go To Services"/>
More specific but still a generic "from-view" configuration:

<navigation-rule>
  <from-view-id>/pages/*</from-view-id>
  <navigation-case>
    <from-outcome>services</from-outcome>
    <to-view-id>/pages/services.jsp</to-view-id>
  </navigation-case>
</navigation-rule>
Navigation with change to URL in browser address bar:

<navigation-rule>
  <navigation-case>
  <from-outcome>services</from-outcome>
    <to-view-id>/pages/services.jsp</to-view-id>
    <redirect/>
  </navigation-case>
</navigation-rule>
Navigate directly (considered an antipattern: does not go through controller, thus no opportunity to initialize the model, etc.)

<h:outputLink value="pages/services.jsp">
  <h:outputText value="Go To Services"/>
</h:outputLink>

EL implicit objects

These give access to web scopes and more: cookie, facesContext, header, headerValues, param, paramValues, request, requestScope, view, application, applicationScope, initParam, session, sessionScope.


Lifecycle

The Lifecycle dictates how an incoming request is handled and how a response is generated. Two "portions" of lifecycle are "execute" and "render", each of which has phases:

  • Execute
    • Finding the View on which to operate (Restore View - initialize new view or restore existing)
    • Allowing components to get their values (Apply Request Values; process events - if conversion errors (from request to local value of component), store message in FacesContext, goto Render Response; if immediate=true, then validation/conversion/event processing is done here)
    • Ensuring the values are converted and validated (Process Validations; if validation errors, store message in FacesContext and goto Render Response)
    • Updating the model (Update Model Values - apply component local values to corresponding server-side object properties; process events; if conversion errors, goto Render Response)
    • Invoke Application - handle application-level events, e.g. submit a form, link to a page, etc.
  • Render
    • process events from Invoke Application phase
    • Selecting and rendering the new view (Render Response)
process events: Ensure any event listeners are called - can declare Response Complete to short-circuit lifecycle. For example, an application might need to redirect to a different web application resource, such as a web service, or generate a response that does not contain JavaServer Faces components. In these situations, the developer must skip the rendering phase by calling FacesContext.responseComplete.

When the life cycle handles an initial request, it only executes the restore view and render response phases because there is no user input or actions to process. Conversely, when the life cycle handles a postback, it executes all of the phases.

You can install PhaseListeners into the Lifecycle to do whatever you want before or after each or every phase. PhaseListeners are registered in a JSF configuration file:

<lifecycle>
  <phase-listener>com.myDomain.MyPhaseListener</phase-listener>
</lifecycle>
Each PhaseListener is global to the application and it subscribes to at least one phase event for every request, thus it is NOT thread-safe.



Event Handlers
  • Action Listeners use the observer pattern - they listen for events on a component (clicked, scrolled, etc). Accept one ActionEvent arg, return void.
  • Value Change Listeners listen for events around component value being changed. Accept one ValueChangeEvent arg, return void.
  • Actions return navigation outcomes. Accept zero-args, return String.

Steps in developing a JSF application
  • Create development directory structure
    • typical webapp layout
    • need JSF 1.2 jars
  • Create config files
    • web.xml
      • add servlet/servlet mapping for Faces Servlet
      • add context-param elements as needed
    • JSF configuration file(s) (a single faces-config.xml by default)
      • nav rules, managed beans, etc.
      • declare custom message.properties file for user-facing messaging
      • create many smaller config files vs one large one, partitioned as appropriate
    • messages.properties
      • override standard JSF messages as needed
  • JSF-specific steps
    • create pages
    • JSF tags: event handlers, validators, converters, messaging, etc.
    • define navigation
    • develop managed beans
    • provide properties, handle events, delegate to business classes, navigation logic
    • Tip: aggregate multiple models into a single managed bean (via compose-and-delegate) to present a facade to JSP
  • Add managed bean declarations
  • Build, deploy, and test the application
  • Iterate on JSF-specific steps and build/deploy/test

Thread Safety
The component will get a new Converter instance each time it is needed when you register a Converter and use a converter tag, thus this is a thread-safe approach:

<converter>
  <converter-id>myConverter</converter-id>
  <converter-class>com.myDomain.myConverter</converter-class>
</converter>

<h:inputText value="#{managedBean.value}" >
  <f:converter converterId="myConverter" >
</h:inputText>  
Using the converter attribute however could introduce a race condition because it is possible the same Converter instance will be used simultaneously by more than one request.

<managed-bean>
  <managed-bean-name>myConverter</managed-bean-name>
  <managed-bean-class>com.myDomain.myConverter</managed-bean-class>
  <managed-bean-scope>session</managed-bean-scope>
</managed-bean>

<h:inputText value="#{myBean.value}" converter="#{myConverter}" /> 
Custom Validators have the same thread safety constraints as custom Converters.


View-State Encryption

By default, view state will not be encrypted. However, there is a way to do this with Mojarra. Specify a environment entry like so:

<env-entry>
  <env-entry-name>ClientStateSavingPassword</env-entry-name>
  <env-entry-type>java.lang.String</env-entry-type>
  <env-entry-value>[SOME VALUE]</env-entry-value>
</env-entry>
The presence of this JNDI entry will cause the state to be encrypted using the specified password...this isn't the most secure way of conveying a password, however, this cannot be accessed easily without having code executed on the server side.


Monday, May 11, 2009

Some notes on a JSF-related fix

It's late on a Friday and I've just solved a JSF headache, so I'm going to quickly write this up while it's still fresh in my mind (the solution, not the headache).

You may have stumbled onto this message if you're developing in JSF or just vanilla JSP:

#{..} is not allowed in template text

When you Google this phrase, you'll find various chunks of advice around versions of JSP, deferred expressions and the Unified Expression Language that comes with JSP 2.1. In particular, this reference appeared to have the definitive fix for my problem: either change the "#{" to "${", or backslash-escape the "#{" sequence, or change a setting to allow deferred syntax as literal. Now, any or all of these solutions might work for you, depending on your context; but I write this up because none of them worked for me.

What I have is a web application developed with JSF 1.1 that had used JSTL 1.1, but that then got deployed into a Java EE 5 environment which provides JSF 1.2 and JSTL 1.2. Many of you already know where this is going. But for my own future reference and possibly your amusement, I'm going to write it up anyway.

I changed all occurrences of #{ to ${, and knowing that Java EE 5 servers already supply the correct JSTL 1.2 version, I removed my webapp's private copies of jstl.jar and standard.jar (vestiges from when they were needed, with J2EE 1.4 servers), but now I get this error message:

According to TLD or attribute directive in tag file, attribute rendered does not accept any expressions

So the syntax change was a head-fake, at least in my case; I can't explain why. You are invited to chime in if you understand it. I was referred to one useful discussion that contains various suggested solutions and references various other threads, and it got me on the right track. Here's what I ended up doing: first, change the ${ back to #{, since really getting the incorrect JSTL version out of the way is the true fix. There is also an EL expression factory workaround discussed in that thread which was applied to my deployment descriptor.

But, here's where it gets interesting (as if it isn't already drop-dead compelling, right?) -- although removing the JSTL 1.1 stuff, applying the DD workaround and reverting back to #{ syntax should have cured all my problems, now I get an EL parsing error concerning this particular attribute construction:

text="#dds.value.enabled?isnsMsg.deactivate_action:isnsMsg.activate_action}"

This is a boolean expression managing a text value that must change depending on the state of a given backing bean property; this had worked just fine in my JSF 1.1 deployment, but now it's no good. The error reads something like this:

Was expecting one of:
"(" ...
<identifier> ...
<namespace> <identifier> "(" ...
Without belaboring the point - since I have a headache from all the different things I tried - I'll just admit it: I took the inelegant way out and used two panel-grouping blocks, each with its own rendered-if attribute, to fix this problem (I'm using tags from the Woodstock JSF component set):
<ui:panelGroup rendered="#{dds.value.enabled}">
    <ui:hyperlink text="#{isnsMsg.deactivate_action}"/>
</ui:panelGroup>
                                       
<ui:panelGroup rendered="#{!dds.value.enabled}">
    <ui:hyperlink text="#{isnsMsg.activate_action}"/>
</ui:panelGroup>
Using JSTL IF and WHEN testing is just as ugly, but at least it fails to work. The JSTL expressions get evaluated too soon relative to the JSF lifecycle, i.e. the IF and WHEN always yield false since they're evaluated before the backing bean property gets its value set as needed.

I didn't do any research to understand why the inline boolean expression in JSF 1.1 caused a parsing error in JSF 1.2 (or maybe it's a JSP 1.2 vs JSP 2.0 thing...hey, probably it's JSTL 1.1 vs 1.2...isn't web-tier fun?). So while I've solved the immediate problem, I've left plenty of room for colleagues to elaborate and, frankly, to correct me where I'm misleading. Like I say, it's late on a Friday and sometimes I do as little as necessary to get from A to Z. If anyone has additional insights around what's discussed here, you are invited to share.