My blog has moved!

You should automatically be redirected in 6 seconds. If not, visit
http://blogs.i2m.dk/allan
and update your bookmarks.

Monday, 16 March 2009

Sending files through action listeners

For this weeks JSF tip, I’ll show you how to send binary data (such as a file) to the user by way of an action handler or listener.

Say, you want to generate a custom PDF and send it to the user as he clicks a link. You need a JSF page, and a backing bean.

Your JSF page may look like this:

<h:form>
    <h:commandLink id="lnkDownload"
                   actionListener="#{myBean.onDownload}"
                   target="_blank"
                   value="Download PDF"  />
</h:form>



Your JSF backing bean may look like this:
public MyBean {

    public void onDownload(ActionEvent event) {
         try {
            // here you need to get the byte[] representation of 
            // the file you want to send
            byte[] binary_data = ;
            String filename = "generated_file.pdf”;
            FacesContext fctx = FacesContext.getCurrentInstance();   
            ExternalContext ectx = fctx.getExternalContext();
            
            HttpServletResponse response = (HttpServletResponse) ectx.getResponse();
            response.setHeader("Content-Disposition", "attachment; filename=\"" + filename + "\"");
            response.setHeader("Content-Transfer-Encoding", "Binary");
            response.setHeader("Pragma", "private");
            response.setHeader("cache-control", "private, must-revalidate");
        
            ServletOutputStream outs = response.getOutputStream();
            outs.write(binary_data);
            outs.flush();
            outs.close();
            response.flushBuffer();
            
            fctx.responseComplete();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
}


That’s it for today.

P.S. alternatively you can use this component which is less code intensive: http://kenai.com/projects/scales/pages/Download

Monday, 9 March 2009

JSF and I18N

It has been a busy year so far. Every year I start out thinking that I really need to relax because the previous year was too hectic, but every year it ends up being much more hectic. Anyway, I thought I’d post a JSF quick time that might shave some headache for people developing internationalised applications.

Most JSF developers are aware of the resource-bundle tag in faces-config. Using this tag you can specify a resource bundle that should be available to all your pages using a given variable. For example, the code below will make a variable, msgs, available in all your pages without having to use the loadBundle tag.

<faces-config version="1.2">
...
    <application>
        <resource-bundle>
            <base-name>my.class.path.Messages</base-name>
            <var>msgs</var>
        </resource-bundle>
    </application>
...
</faces-config>


So, say that Messages.properties contains the following:

HELLO_WHAT_IS_YOUR_NAME=Hello, what’s your name?
 


you can from any page reference this text by writing:

<h:outputText value=”#{mgs.HELLO_WHAT_IS_YOUR_NAME}” /> 

or
<h:outputText value=”#{mgs[‘HELLO_WHAT_IS_YOUR_NAME’]}” />


I prefer the former as my favourite IDE (NetBeans) support code completion for all the messages in a managed resource bundle.

So far so good. But what if you want to do something a bit more advanced, such as outputting “Hello Allan, welcome to my site. Your last visit was 7. February 2009 at 10:45”. You are not limited to static text in your resource bundle. You can provide placeholders for content that will be replaced at run-time. Let’s have a look at the Message.properties:

WELCOME_MESSAGE=Hello {0}, welcome to my site. Your last visit was {1,date,long} at {1,time,short}


You’ll notice that the message is parameterised using two parameters. The first parameter we are expecting a string containing the name of the user, the second parameter is a java.util.Date containing both the date and time when user last visited the site. Notice that I’ve reused the second paramenter ({1}), one time for the date and the other for the time. On your JSF page you would use the message as follows (imaging that you have a bean called welcome containing a property for getting the name of the user and last visit):

<h:outputFormat value=”#{msgs.WELCOME_MESSAGE}”>
    <f:param value=”#{welcome.userName}” />
    <f:param value=”#{welcome.lastVisit}” />
</h:outputFormat>    


Pretty neat, eh?

What about the classical case of singular and plural messages? Imagine that you want to display the number of records in a table “There are 10 records in the table”. If the Message.properties contained:

RECORDS_IN_TABLE=There are {0} records in the table


You’d end up an embarrassing problem if there was only one record in the table:

“There are 1 records in the table” (This sentence is grammatical incorrect)

Instead you would want it to output:

“There is 1 record in the table”

To do this, you have to use the choice pattern:

RECORDS_IN_TABLE=There {0, choice, 0#are|1#is|2#are} {0} {0, choice, 0#records|1#record|2#records}


The format might look a bit awkward, but once you have understood the pattern it is simple:


{0,choicemeans, taking the first parameter and base the output on a choice of formats
0#areif the first parameter contains 0 (or below), then it should print “are”
|1#isor, if the first parameter contain 1, then it should print “is”
|2#are}or, if the first parameter contains 2 (or above), then it should print “are”


Now, that is nice! So let’s examine the output of these examples:

<h:outputFormat value=”#{msgs.RECORDS_IN_TABLE}”>
    <f:param value=”#{0}” />
</h:outputFormat>
There are 0 records in the table
<h:outputFormat value=”#{msgs.RECORDS_IN_TABLE}”>
    <f:param value=”#{1}” />
</h:outputFormat>
There is 1 record in the table
<h:outputFormat value=”#{msgs.RECORDS_IN_TABLE}”>
    <f:param value=”#{2}” />
</h:outputFormat>
There are 2 records in the table
<h:outputFormat value=”#{msgs.RECORDS_IN_TABLE}”>
    <f:param value=”#{10}” />
</h:outputFormat>
There are 10 records in the table


Enjoy!