DigitalJoel

2010/09/12

JSF graphicImage from database

Filed under: development, facelets, java, JSF, JSF2 — digitaljoel @ 8:45 pm

I’ve seen some questions on the webtier mailing list about loading image resources from a database, but no real implementation suggestions.  I ended up needing to figure this out for work, and got permission to post the solution here.  It’s not 100% complete as it doesn’t allow for caching at the client or in the JSF layer, but it’s a starting point.  You won’t be able to take this solution and simply plop a jar in your project and make it go.  You’ll have to implement your own solution, but can base it on this information if it helps you.

In my case, our software manages Programs and Brands.  What those entities represent isn’t important, but know that each program can have a logo and custom css, and each Brand can have a logo.  I wanted to be able to use the regular JSF tags to output these images so the designers wouldn’t have to learn a new tag.  Something like this:


    <h:outputStylesheet library="program_#{user.programName}" name="css" />
    <h:graphicImage library="program_#{user.programName}" name="logo" />

The first step is to implement a custom ResourceHandler.  This would be super awesome if we could just extend ResourceHandlerWrapper like the JSF developers intended.  They built that class precisely for extension, unfortunately, the implementation has what I consider a fatal flaw.  JSF calls handleResourceRequest in order to create a resource when a resource request comes in.  The resource is a representation of your image or css.  In handleResourceRequest, the ResourceHandlerWrapper calls in to the wrapped instance’s handleResourceRequest, and the ResourceHandlerImpl  handleResource calls its own createResource method.

Update: It looks like they have fixed the ResourceHandlerImpl in 2.0.3 so that it now delegates to the configured resource handler for createResource.  This is great in that it means you should be able to now extend ResourceHandlerWrapper instead of ResourceHandlerImpl and get the correct behavior.  You should view this thread http://forums.java.net/jive/thread.jspa?threadID=153490&tstart=0 for more info.

So, if my extension of ResourceHandlerWrapper implements its own createResource method in order to create my own custom resources, then I must also implement my own handleResourceRequest which, if you look at the linked javadoc would be really easy to mess up all resource handling in your application.

The point of all this rambling?  I had to do something I’m not proud of.  I extended ResourceHandlerImpl, which is a non-published API, but it was that or implement my own handleResourceRequest, which I really didn’t want to do.  So, here’s the source of my ResourceHandler.


package yourpackage.jsf;

import com.sun.faces.application.resource.ResourceHandlerImpl;
import javax.faces.application.Resource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author Joel.Weight
 */
public class DelegatingResourceHandler extends ResourceHandlerImpl
{
    private ResourceHelper[] helpers = new ResourceHelper[] {
    new ProgramResourceHelper()
    , new BrandResourceHelper()
    };

    private static Log log = LogFactory.getLog( DelegatingResourceHandler.class );

    @Override
    public Resource createResource( String resourceName, String libraryName )
    {
        ResourceHelper helper = getHelper( libraryName );
        if ( helper != null )
        {
            return helper.createResource( resourceName, libraryName );
        }
        // otherwise delegate to the default implementation.
        if ( log.isDebugEnabled() )
        {
            log.debug( "Delegating resource creation to default implementation. name: " + resourceName +
            " and library: " + libraryName );
        }
        return super.createResource( resourceName, libraryName, null );
    }

    @Override
    public boolean libraryExists( String libraryName )
    {
        ResourceHelper helper = getHelper( libraryName );
        if ( helper != null )
        {
            return true;
        }
        return super.libraryExists( libraryName );
    }

    /**
    * Get the helper that handles a given library.
    * @param libraryName
    * @return
    */
    private ResourceHelper getHelper( String libraryName )
    {
        for ( ResourceHelper helper : helpers )
        {
            if ( helper.handlesLibrary( libraryName ))
            {
                return helper;
            }
        }
        return null;
    }
}

Alright, what’s going on here.  First, an array of ResourceHelpers.  Since I want to load images from different entities, I have a helper for each one, which will be responsible for instantiating the resource for the given entity.

Next, the createResource method asks each helper if it handles a given library.  Each helper has a prefix that signals to it that it should handle a given resource request.  For instance, program_ and brand_ are the prefixes I have.  If none of the helpers handle the library, then it delegates to the default handler functionality.

Finally libraryExists asks each helper if it handles the given library.  If none of them, then it delegates to the default handler functionality.

Next is the helper implementation.  I created an abstract class so the Program and Brand helpers could share common functionality.  Here it is.


package yourpackage.jsf;

import javax.faces.application.Resource;
import javax.faces.context.FacesContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author Joel.Weight
 */
public abstract class ResourceHelper
{

    protected String prefix;

    private static Log log = LogFactory.getLog( ProgramResourceHelper.class );

    public ResourceHelper( String prefix )
    {
        this.prefix = prefix;
    }

    /**
     * Create a resource with the given name for the given library
     * @param resourceName The resource name, as passed in the JSF tag
     * @param libraryName The library name, as passed in the JSF tag
     * @return The resource, or null if not found.
     */
    public abstract Resource createResource( String resourceName, String libraryName );

    /**
     * remove the prefix from a resourceName
     * @param name resourceName
     * @return the resource name without the prefix, or the original string if it doesn't start with the prefix.
     */
    public String stripPrefix( String name )
    {
        if ( name != null && name.startsWith( prefix ))
        {
            return name.substring( prefix.length() );
        }
        return name;
    }

    /**
     * Test whether this helper handles the given library name.
     * @return true if this helper handles the library, false otherwise.
     */
    public boolean handlesLibrary( String libraryName )
    {
        boolean result = ( libraryName != null
                                && libraryName.toLowerCase().startsWith( prefix )
                                && libraryName.length() > prefix.length());
        if ( log.isDebugEnabled() )
        {
            log.debug( String.format( "Helper with prefix %s handles library %s : %s", prefix, libraryName, result ));
        }
        return result;
    }

    /**
     * Gets a bean from the faces context.
     * @param name name of the bean to get
     * @return bean instance as returned from faces context.
     */
    public Object getBeanFromFacesContext( String name )
    {
        FacesContext context = FacesContext.getCurrentInstance();
        return context.getApplication().getELResolver().getValue( context.getELContext(), null, name );
    }
}

This is pretty simple.  It takes care of a lot of the prefix handling stuff.  The handlesLibrary method is the biggest shared functionality.  It looks at the prefix and determines if the library passed in the graphicImage or outputStylesheet tag should be handled by this helper.

Here is an implementation of the abstract class.  This is the one for Brand.


package yourpackage.jsf;

import awp.data.BrandService;
import awp.view.Brand;
import javax.faces.application.Resource;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * ResourceHelper for getting images associated with a Brand.
 * @author Joel.Weight
 */
public class BrandResourceHelper extends ResourceHelper
{

    private BrandService brandService;

    private static Log log = LogFactory.getLog( BrandResourceHelper.class );

    public BrandResourceHelper()
    {
        super( "brand_" );
    }

    @Override
    public Resource createResource( String resourceName, String libraryName )
    {
        Brand brand = getBrandByLibraryName( libraryName );
        if ( brand != null )
        {
            return new BrandResource( resourceName, libraryName, brand );
        }
        return null;
    }

    private Brand getBrandByLibraryName( String libraryName )
    {
        Brand brand = null;
        String brandName = stripPrefix( libraryName );
        if ( brandName != null && brandName.length() > 0 )
        {
            brand = getBrandService().findBrandByName( brandName );
        }
        return brand;
    }

    private BrandService getBrandService()
    {
        if ( brandService == null )
        {
            brandService = (BrandService)getBeanFromFacesContext( "brandService" );
        }
        return brandService;
    }
}

As with the others, it’s quite simple, and the Program implementation looks very similar.  The only thing we really have to implement here is the constructor which sets up the prefix, and the createResource method.  The others are all helper methods.  createResource finds our entity in order to get the image from it.  Your implementation could query for just the image, or do whatever you want here.

Next up is our custom resource implementation.  This one is a little longer because we are extending a fair amount of the functionality in Resource


package yourpackage.jsf;

import yourpackage.DataObject;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.faces.application.Resource;
import javax.faces.application.ResourceHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * base representation of a database backed resource.
 */
public abstract class DataObjectResource<T extends DataObject> extends Resource
{
    protected String name;
    protected String libraryName;
    protected T dataObject;

    private static Log log = LogFactory.getLog( DataObjectResource.class );

    // HTTP Date format required by the HTTP/1.1 RFC
    private static final String LAST_MODIFIED_PATTERN = "EEE, dd MMM yyyy HH:mm:ss zzz";

    public DataObjectResource( String name, String libraryName, T object )
    {
        this.name = name;
        this.libraryName = libraryName;
        this.dataObject = object;
        if ( log.isTraceEnabled() )
        {
            log.trace( "Created new DataObjectResource: libraryName: " + libraryName + " name: " + name );
        }
    }

    /**
    * Get the input stream for this resource.
    * @return
    * @throws IOException
    */
    @Override
    public abstract InputStream getInputStream() throws IOException;

    @Override
    public Map<String, String> getResponseHeaders()
    {
        Map<String, String> result = new HashMap<String, String>( 6, 1.0f );
        SimpleDateFormat format = new SimpleDateFormat( LAST_MODIFIED_PATTERN );
        // make it modified so they always request the whole resource.
        // TODO: make this smarter when going into production.
        result.put( "Last-Modified", format.format( new Date()));
        return result;
    }

    @Override
    public String getRequestPath()
    {
        StringBuilder buf = new StringBuilder(
        FacesContext.getCurrentInstance().getExternalContext().getRequestContextPath() );
        buf.append( ResourceHandler.RESOURCE_IDENTIFIER );
        buf.append( "/" ).append( name ).append( ".faces?ln=" ).append( libraryName );
        if ( log.isDebugEnabled() )
        {
            log.debug( "Request path for program resource " + this.toString() + " : '" + buf.toString() + "'" );
        }
        return buf.toString();
    }

    @Override
    public URL getURL()
    {
        ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
        StringBuilder buf = new StringBuilder( context.getRequestScheme() );
        buf.append( context.getRequestServerName() );
        if ( context.getRequestServerPort() != 80 && context.getRequestServerPort() != 443 )
        {
            buf.append( ":" ).append( context.getRequestServerPort());
        }
        buf.append( getRequestPath());
        URL url = null;
        try
        {
            url = new URL( buf.toString());
            if ( log.isDebugEnabled() )
            {
                log.debug( "Created new URL " + buf.toString() + " for ProgramResource " + this.toString() );
            }
        }
        catch( java.net.MalformedURLException e )
        {
            log.error( "Unable to create URL for ProgramResource " + this.toString(), e);
        }
        return url;
    }

    @Override
    public boolean userAgentNeedsUpdate( FacesContext fc )
    {
        // TODO: always updates the user agent.  fix this to allow for caching.
        return true;
    }

    @Override
    public String toString()
    {
        return String.format( "%s { name=%s libraryName=%s }"
        , this.getClass().getName()
        , name
        , libraryName );
    }
}

This class is pretty dumb, and needs the most help to make it usable in a production system.  It provides default implementations for all of the methods of the Resource, except the getInputStream method.  The good news is that when I get time to come back to this class, it’ll be smarter for every implementation of this abstract class.

Now, to a concrete implementation of our custom Resource class.  This time we’ll look at ProgramResource since it handles css and an image.  I also have an implementation for BrandResource.


package yourpackage.jsf;

import yourpackage.Program;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * JSF Resource implementation used to get information from a Program in the database.
 */
public class ProgramResource extends DataObjectResource<Program>
{
    /**
    * Use this resource name in JSF to get the program logo.
    */
    public static final String LOGO_RESOURCE = "logo";

    /**
    * Use this resource name in JSF to get the program css.
    */
    public static final String CSS_RESOURCE = "css";

    private static Log log = LogFactory.getLog( ProgramResource.class );

    public ProgramResource( String name, String libraryName, Program program )
    {
        super( name, libraryName, program );
    }

    @Override
    public InputStream getInputStream() throws IOException
    {
        if ( LOGO_RESOURCE.equals( this.name ))
        {
            return new ByteArrayInputStream( dataObject.getLogo() );
        }
        else if ( CSS_RESOURCE.equals( this.name ))
        {
            return new ByteArrayInputStream( dataObject.getCss().getBytes());
        }
        else
        {
            if ( log.isWarnEnabled() )
            {
                log.warn( "Attempted to get input stream for ProgramResource, but no correct name specified. " +
                this.toString() );
            }
            return null;
        }
    }
}

First, notice the final static Strings that identify logo and css.  Those are the names of the resources you will use in the graphicImage and outputStylesheet tags.  They tell me where to get the data from for the getInputStream method.  The implementation of getInputStream is quite simple.  We just look at the name of the resource being requested, and use that as a key to figure out which field of our DataObject.

The last part of this puzzle is to tell JSF to use our DelegatingResourceHandler that we implemented at the start.  This is done with the following tag in your faces-config.xml file.  It should be within the application tag.


<resource-handler>yourpackage.jsf.DelegatingResourceHandler</resource-handler>

With all of this in place, I can show a different image in the same place in my application depending on the current context, and pull that image from the database.  For instance, if one user is in Program A, and another is in Program B, I simply use the user’s context to give the program to the graphicImage tag, and the outputStylesheet tag, and I have different styling and images for each of those users, without changing anything in my xhtml.

As I said before, this implementation is far from perfect.  If you attempt to reference a resource library and the helper can’t find it in the database then you will have a problem.  Also if you attempt to reference a resource name that doesn’t tie in to one of your identifiers in your Resource implementation, then you are toast.  Finally, there is no caching currently, so every request will load the image or css from the database.  That’s ugly.  Perhaps when I get back to this code in my current project, I’ll update the source in this blog post.  In the meantime, it ought to be a decent starting point for anyone looking to solve the same problem.

Advertisements

2010/01/11

JSF 2 Custom Converter

Filed under: development, facelets, GAE, java, JSF — Tags: , , , — digitaljoel @ 9:50 pm

I ran into a very strange problem in my little Google App Engine application. I’m using JSF 2 as the presentation layer. I’m using Google’s low level api for accessing the data store and have written some little utilities to convert from my objects to Google’s Entity objects.

I thought I had the mapping working OK, but had only tried setting simple String properties on my data objects. I finally tried to map a simple association, where one object would have a list of keys of other objects. In my case I have Tables. Each table can be associated with zero or more Genres. So, my Table data object has a List of Keys for the genres that it is a part of, like this:

public class Table
        extends DataObjectAbstract
        implements Serializable
{
    @Persistent
    private List<Key> genres;

    // other private attributes here

    public List<Key> getGenres()
    {
        return genres;
    }

    public void setGenres( List<Key> genres )
    {
        this.genres = genres;
    }

    // other public getters and setters and other methods here
}

You can safely ignore DataObjectAbstract and the @Persistent annotation. They aren’t part of this blog post.

The strange behavior I was seeing was that when I would get the genre list from the data store, it would be a List<String> instead of the List<Key> I was expecting. After some debugging, I finally discovered that I was setting it as a List<String> because Strings are what I was getting from my JSF page, and thanks to Java’s type erasure with generics, my code didn’t know any better. So, the solution is a custom converter, which will allow me to pass the Keys to and from the browser.

Fortunately, in JSF 2, custom converters are even easier than they are in JSF 1.x. Here’s my simple converter class for the com.google.appengine.api.datastore.Key class. Making this even more simple is the fact that Google offers a KeyFactory that takes care of giving a URL safe representation of their Key object.

package jota.soc.ui.converter;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

/**
 * Converter for Google Key.
 * @author Joel.Weight
 */
@FacesConverter( value="keyConverter" )
public class KeyConverter implements Converter {

    /**
     * converts the String representation of the key back to the Object
     */
    public Object getAsObject( FacesContext context, UIComponent component,
                               String value )
    {
        // will throw new IllegalArgumentException if it can't parse.
        return KeyFactory.stringToKey( value );
    }

    /**
     * converts the Key object into its String representation.
     */
    public String getAsString( FacesContext context, UIComponent component,
                               Object value )
    {
        if ( value instanceof Key )
        {
            return KeyFactory.keyToString( (Key)value );
        }
        else
        {
            throw new IllegalArgumentException( "Cannot convert non-key object in KeyConverter" );
        }
    }
}

With the @FacesConverter annotation, you don’t have to register the converter in faces-config or anything. You can simply reference it using the id.

Here’s the code that uses the converter.

<h:selectManyListbox id="genresBox" value="#{createTable.table.genres}">
    <f:converter converterId="keyConverter" />
    <f:selectItems value="#{createTable.genres}"
        var="item"
        itemValue="#{item.key}"
        itemLabel="#{item.name}" />
</h:selectManyListbox>

And just like that, I’m storing Keys in the data store instead of Strings.

2009/12/21

JSF 2.0.2 and Google App Engine

Filed under: facelets, GAE, java, JSF — Tags: , — digitaljoel @ 6:46 pm

I spent a couple hours today trying to get a JSF 2 based webapp up in app-engine.  Of course, it wasn’t as easy as simply following the instructions in

configuring jsf 2.0 to run on the google app engine using netbeans

I ran into the problem detailed here  ( JNDI problem in jsf 2.0 and google app engine ) right off the bat.  I tried to use his packaged jar, but app-engine kept giving me an exception that it couldn’t load the zip file. Perhaps it was corrupted when I downloaded it or something.

If you follow his link to the WebConfiguration.java file, you will see that he created a new WebConfiguration.java file within the same package as the existing one and copied the implementation, commenting out the offending code.  I decided to try a different approach. I’m sure there is nothing wrong with Josh’s approach, and if it weren’t for his blog and all the ground work he had already done in finding the offending code, I probably wouldn’t have even bothered going further with JSF 2 in app engine. In any case, here’s what I did.

I downloaded the JSF 2.0.2 source from here ( jsf 2.0.2 source ) and expanded it.  I then found the WebConfiguration.java file and decided to modify it.  Rather than comment out all the source, I added a new config enumeration value to the BooleanWebContextInitParameter enumerations as follows

// around line 1071 in the finished file, after the previously final enum value AllowTextChildren
EnableJNDI(
"com.sun.faces.enableJNDI",
true
);

Then, I check for the value of that parameter in private constructor, around line 113

        // add the isOptionEnabled call to this conditional statement
        if ( isOptionEnabled( BooleanWebContextInitParameter.EnableJNDI ) && canProcessJndiEntries()) {
            processJndiEntries(contextName);
        }

When that is done, simply compile, and you have a new jsf-api/build/lib/jsf-api.jar and jsf-ri/build/lib/jsf-impl.jar that you can use in your project. For my compile, I simply copied the build.properties.glassfish.orig to build.properties and set the jsf.build.home property to the directory in which the source was checked out.

Finally, put a new context-param in web.xml with the name com.sun.faces.enableJNDI and a value of false.

All I’ve got so far is the hello world, so we’ll see if I run into other difficulties as I use further functionality.

2009/12/14

Sharing JSF 2 Composite Components

Filed under: development, facelets, JSF — Tags: , — digitaljoel @ 4:25 pm

Let’s say you have created some awesome composite components in JSF 2 that you want to share between one webapp and another.  One option would be to simply copy all of the .xhtml files from one webapp to the other.  Yuck.  Then you have two versions of each file.  Changes in one are not reflected in the other, and what happens when you are up to 6 webapps that all want to share your awesome components?  That’s ugly.

A better solution is to jar them all up into a new component library.  Sounds complicated huh?  Not really.

Each of your composite components should be in a resources directory.  In order to redistribute those components, you simply add them to a jar under META-INF/resources, and then make sure that your META-INF directory also contains a faces-config.xml file.

The faces-config.xml file ensures that JSF scans the jars for components and annotated classes.  The following ant target, which I added to the build.xml file in a netbeans project automatically takes the resources directory, and creates an empty faces-config.xml file and plops them into a jar.  Now, you simply include that jar as a library in your new webapp.

    <target name="create-lib-jar">
        <property name="stage-dir" value="create-lib-jar-temp" />
        <property name="dist.dir" value="." />
        <property name="lib.jar" value="${dist.dir}/jsfLibrary.jar" />
        <mkdir dir="${stage-dir}" />

        <echo file="${stage-dir}/faces-config.xml" ><![CDATA[<?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_2_0.xsd"
    version="2.0">
</faces-config>]]></echo>

        <jar destfile="${lib.jar}">
            <metainf dir="${stage-dir}">
                <include name="faces-config.xml" />
            </metainf>

            <metainf dir="web" includes="resources/">
            </metainf>

        </jar>

        <delete dir="create-lib-jar-temp" />

    </target>

Think of the possibilities.  Now, you have a simple project in which to build your core, re-usable composite components, all running in their own little webapp, testable with junit for the java classes and selenium for the web portions.  Then, you package them up for use in all your webapps.  That’s awesome sauce.

This build target doesn’t get any java class files.  When I get to that part of my project, I’ll update it.

Make sure to modify the properties to fit your environment so it is pulling from the correct directories and all that jazz.

<target name=”create-lib-jar”>
<property name=”stage-dir” value=”create-lib-jar-temp” />
<property name=”dist.dir” value=”.” />
<mkdir dir=”${stage-dir}” /> 

<echo file=”${stage-dir}/faces-config.xml” ><![CDATA[<?xml version=’1.0′ encoding=’UTF-8′?>
<faces-config
xmlns=”http://java.sun.com/xml/ns/javaee&#8221;
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance&#8221;
xsi:schemaLocation=”http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd&#8221;
version=”2.0″>
</faces-config>]]></echo>

<jar destfile=”${dist.dir}/jsfLibrary.jar”>
<metainf dir=”${stage-dir}”>
<include name=”faces-config.xml” />
</metainf>

<metainf dir=”web” includes=”resources/”>
</metainf>

</jar>

<delete dir=”create-lib-jar-temp” />

</target>

2009/09/28

Using ui:insert to include children

Filed under: facelets, JSF — digitaljoel @ 10:20 pm

Let’s say you have a custom facelets component that wraps an h:selectOneListbox. As a part of using this component, you read the list of items that should be displayed in the list from a database table. Your bean reads the results of the database query and creates listItems, that are then passed back to the h:selectOneListbox, through your my:customListbox component. For instance:

            <my:customListbox
              fieldName="itemValue"
              entity="#{myBean}"
              items="#{myDatabaseBean.listItems}" />

In this example, the value of the h:selectOne would be set in myBean.setItemValue, and the list of selectItems would be returned from myDatabaseBean.getListItems.

Now, you decide that you want to provide some defaults for the lists that are in your UI, but not in the database. You could modify myDatabaseBean.getListItems to manually add a custom default selectItem. The value of the defaultItem could be null, or empty string, that way, when the list is displayed, if myBean.getItemValue returns null or empty string, the default value would be selected in the UI. Pretty slick, except for you have to write java in EVERY instance where you are creating your listItems from the database. Now, add in internationalization and your database bean now has to use the correct resource bundle to read the default value display string. That’s not real difficult, but it’s just more java code that has to be introduced everywhere you are creating those lists.

So, is there another way? Here’s what I did.

In my customListbox component I included a well placed, anonymous ui:insert. This magically made my composition include the children of my customListbox in place of the unnamed ui:insert. For instance, within customListbox.xhtml my h:selectOneListbox now looks like this:

    <h:selectOneListbox value="#{entity[fieldName]}">
      <ui:insert />
      <f:selectItems value="#{items}" />
    </h:selectOneListbox>

Then I can include multiple f:selectItem elements as a child of my:customListbox such as:

<my:customListbox
    fieldName="itemValue"
    entity="#{myBean}"
    items="#{myDatabaseBean.listItems}" >
    <f:selectItem itemValue="" itemLabel="#{bundle.defaultBlahValue}" />
</my:customListbox>

Now, I’ve been able to add a custom default value to my custom listbox with a single line in xhtml, and a single resource bundle value, and no java.

2009/08/25

Passing action methods in Facelets using array notation

Filed under: facelets, java, JSF — digitaljoel @ 3:21 am

When I was first learning facelets, I often ran into a problem when I was passing an action method into an included facelet file. For instance, I had file1.xhtml, which would include my custom tag component file2.xhtml (defined within my taglib.xml file.) file2.xhtml had a commandLink or commandPrompt that needed an action. Since I would re-use file2.xhtml and allow it to call different actions, I needed a way to pass the action method to file2.

The first thought was to include it as an attribute of my component.

<myns:mytag
   myActionAttribute="${mybean.myaction}" />

and then within file2, which in this case is mapped to mytag:

<h:commandLink value="${mybean.myValue}" action="${myActionAttribute}" />

When I tried to execute this, faces would complain to me that mybean had no myaction property. I knew it did and would be endlessly frustrated by this.
The answer is to reference the action method using array notation. On any bean referenced in facelets you can reference the properties using dot notation, as in ${mybean.myaction}, OR you can also reference it using array notation, such as ${mybean[“myaction”]}.
I never did dig in far enough in order to figure out exactly what was going on under the hood, but I’m guessing ${mybean.myaction} was actually evaluated before being sent to mytag. In order to avoid this, pass the bean, and then pass the action method as a string to the component, such as:

<myns:mytag
   myActionController="${mybean}"
   myActionMethod="myaction" />

Notice that the method is just a string. Then in your component, reference it in array notation ( how many times can I say array notation! )

<h:commandLink value="${mybean.myValue}" action="${myActionController&#91;myActionMethod&#93;}" />

Notice that the method is NOT quoted. myActionMethod will be replaced by the String value passed in the value of the attribute, and that method on the bean will be called as the action of the commandLink.

2009/07/07

JSF Tri State Checkbox

Filed under: facelets, java, jquery, JSF — digitaljoel @ 5:05 am

In my work with JSF I found that I needed a tri-state checkbox.  In my case, the checkbox represented whether or not a decorator was added to all selected objects, no selected objects, or some of the selected objects.  This corresponded to checked, unchecked, or partially checked.

When I was looking for something that would fit my needs I found a Javascript implementation at Shams’ Blog which is a bit of a different use case than what I was looking for, but has some good points and useful images.

I created the following facelet file that manages state transitions and image management for the JSF tri state checkbox.  My control doesn’t handle the nested selection like you’ll see in Sham’s blog, but it fills the needs stated above.

<!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:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jstl/core" >

<!--
  An input component that is represented as a checkbox with three states.  Checked, Unchecked, and Intermediate.

  Required attributes:
    checkedValue - the value that should be set for this component when the checkbox is checked
    uncheckedValue - the value that should be set for this component when the checkbox is unchecked
    intermediateValue - the value that should be set for this component when the checkbox is in the intermediate state.
    value - bean property to hold the value.  Should evaluate to checkedValue, uncheckedValue, or intermediateValue the first time.
    controller - controller that implements the value change listener.
    key - key value to pass as an attribute of the control that contains the checkbox value.
    valueChangeListener - change listener for value of this checkbox component.
 -->

<ui:composition>

  <script type="text/javascript">
    function setCheckValue( img, next, newVal )
    {
      img.css('display', 'none');
      img.siblings('[id$='+next+']').css('display','inline');
      img.siblings('[id$=triStateCheck]').val(newVal);
    }
  </script>

  <h:graphicImage
    id="trueValue"
    url="/images/ico_checked.gif"
    style="display: #{value == checkedValue ? 'inline' : 'none'}"
    onmouseover="jQuery(this).attr('src','/images/ico_checked_highlighted.gif')"
    onmouseout="jQuery(this).attr('src','/images/ico_checked.gif')"
    onclick="setCheckValue( jQuery(this), 'falseValue', '#{uncheckedValue}')"
    rendered="#{(empty rendered) ? true : rendered}" />
  <h:graphicImage
    id="falseValue"
    style="display: #{value == uncheckedValue ? 'inline' : 'none'}"
    onmouseover="jQuery(this).attr( 'src', '/images/ico_unchecked_highlighted.gif' )"
    onmouseout="jQuery(this).attr('src', '/images/ico_unchecked.gif')"
    url="/images/ico_unchecked.gif"
    onclick="setCheckValue( jQuery(this),
        '#{value == intermediateValue ? 'intermediateValue' : 'trueValue'}',
        '#{value == intermediateValue ? intermediateValue : checkedValue}')"
    rendered="#{(empty rendered) ? true : rendered}" />
  <h:graphicImage
    id="intermediateValue"
    style="display: #{value == intermediateValue ? 'inline' : 'none'}"
    onmouseover="jQuery(this).attr( 'src', '/images/ico_intermediate_highlighted.gif' )"
    onmouseout="jQuery(this).attr('src', '/images/ico_intermediate.gif')"
    url="/images/ico_intermediate.gif"
    onclick="setCheckValue( jQuery(this), 'trueValue', '#{checkedValue}')"
    rendered="#{(empty rendered) ? true : rendered}" />

  <h:inputHidden
    id="triStateCheck"
    value="#{value}"
    valueChangeListener="#{controller&#91;valueChangeListener&#93;}">
    <f:attribute name="key" value="#{key}" />
  </h:inputHidden>

</ui:composition>
</html>

The control starts with a very simple script that uses jquery.

    function setCheckValue( img, next, newVal )
    {
      img.css('display', 'none');
      img.siblings('[id$='+next+']').css('display','inline');
      img.siblings('[id$=triStateCheck]').val(newVal);
    }

The script takes three parameters. The current image, the next image, and the new value. It then hides the current image, shows the new image, and sets the value of the control to the new value.

Each image in the control has a couple of Javascript event handlers. One to show the highlighted version of the current image on mouseover, and another to show the regular version on mouse out. Finally, a third to transition to the next state and set the value on click. You’ll notice that in the falseValue image, the onclick is a bit longer than the others.

    onclick="setCheckValue( jQuery(this),
        '#{value == intermediateValue ? 'intermediateValue' : 'trueValue'}',
        '#{value == intermediateValue ? intermediateValue : checkedValue}')"

This is because if the value doesn’t start at intermediate, then we don’t ever want to hit the intermediate value in transitions. For instance, if the value starts at true or false, the checkbox will function just like a normal checkbox, toggling only between true and false. If the checkbox starts at the intermediate value, then it will go from intermediate to true, then to false, then back to intermediate on subsequent clicks. If this is not the desired behavior, then the conditional statements in the onclick can be removed so that it always goes to intermediate.

The final interesting part of the control is the hidden field that holds the value of the checkbox.

  <h:inputHidden
    id="triStateCheck"
    value="#{value}"
    valueChangeListener="#{controller&#91;valueChangeListener&#93;}">
    <f:attribute name="key" value="#{key}" />
  </h:inputHidden>

This inputHidden control contains the current value of the checkbox. The value is set initially, and then changed through javascript when the checkboxes are clicked. When debugging, it can be helpful to change the inputHidden to a simple input text control so you can inspect it and see the value change. The control will call a value change listener which can use the key attribute to determine which entity the checkbox belongs to. This is valuable when you are stamping the checkboxes ( as in a ui:repeat ) so you know which entity in the collection had the checkbox changed.

In order to use the control, simply save the text to a file and include a pointer to it in your JSF taglib definition. You can modify the image paths for your needs and set the other attributes as they are commented at the top of the file.

Suggestions on how to improve this control? I’d love to hear them.

2009/02/05

Accessing Map Entries With Dot Notation

Filed under: facelets, java, JSF — digitaljoel @ 3:03 am

This may be something that is old news to everyone else in facelets, but I just found out that you can access map entries using dot notation in facelets code.  Where is this handy?

Let’s say you have a facelets component that you wrote to display certain properties of a complex java object.  The component looks something like this.

<ui:composition>
    <!-- various styling, action, etc. -->

    <h:outputText value="#{entity.myValue}" />
    <h:outputText value="#{entity.yourValue}" />

    <!-- various styling, actions, etc. -->
</ui:composition>

You now decide that you like the formatting and actions in this component and want to use it with something else.  You don’t want to add myValue and yourValue to your other entity, nor do you want to create a facade or container class that just contains those properties that you are using in the facelets component.

One solution would be to create a map that contains the values you need for the component.  This doesn’t require a new concrete Java object and allows you to re-use the facelets component.

So, in the facelets page or component that includes your custom component you could do the following

<z:myComponent entity="#{myBean.propertyMap}" />

And in your controller bean or whatever, you could have a simple method

public Map<String, String> getPropertyMap()
{
    // get your entity
    Map<String, String> map = new HashMap<String, String>();
    map.put( "myValue", myEntity.getSomethingForMyValue() );
    map.put( "yourValue", myEntity.getSomethingForYourValue() );
    return map;
}

Now, the awesome magic is that the facelets component above will be able to reference the map values by name using dot notation in the component.  It doesn’t care if the “entity” you pass in is a simple map, or a Java object with proper getters and setters for the properties.

Blog at WordPress.com.