My blog has moved!

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

Showing posts with label Quick tip. Show all posts
Showing posts with label Quick tip. Show all posts

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!

Wednesday, 31 December 2008

Setting JAVA_HOME on Ubuntu

A thing that always annoys me about installing Java is that it doesn't automatically set up the JAVA_HOME environment variable after installation. I guess this is to avoid having problems when you have multiple virtual machines installed. Anyway, I use Ubuntu Linux to host the majority of my Java Application Server. It is easy install Java (sudo apt-get install sun-java6-jdk) but there always seems to be a debate about where to set the JAVA_HOME environment variable. Some instructions say you should add it to your personal profile (e.g. ~/.bashrc) others suggest adding it to the global profile (i.e. /etc/profile), some people even suggest adding it directly in the init script for the services that need the variable. My suggest is to add an executable shell script to /etc/profile.d/ called javahome.sh. The content of the file would be: export JAVA_HOME=/usr/lib/jvm/java-6-sun. All shell scripts (i.e. executable files with the extension .sh) located in the /etc/profile.d/ directory are loaded upon login and would therefore work for all users without having to change system files that may change upon the next O/S upgrade. To test the script simply type source /etc/profile This will reload the profile for the current user. To verify that the environment variable has been initialised type export|grep JAVA_HOME

Enjoy!

Monday, 24 November 2008

Getting value expressions from f:attributes

If you have a custom converter or validator you may provide these with the option of letting developers specify attributes. For example, let's say that we are creating a converter that will allow the formatting of a Calendar object. Note, that the <f:convertDateTime /> is for Date objects (which can be easily retrieved from a Calendar, but that is beside the point). So the custom converter I'll create here is for converting/formatting Calendar objects.


package com.blogspot.bigallan.converters;

import java.text.*;
import java.util.*;
import javax.el.ValueExpression;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;

public class CalendarConverter implements Converter {

/**
* Not implemented as the converter is one-way only.
*/
public Object getAsObject(FacesContext ctx, UIComponent component, String value) {
return null;
}

public String getAsString(FacesContext ctx, UIComponent component, Object value) {

// Get the Calendar to convert
Calendar calendar = (Calendar) value;

String pattern = "";

// Obtain attributes specified along with the converter
Map<String, Object> attributes = component.getAttributes();

// Check if the pattern attribute was specified
if (!attributes.containsKey("pattern")) {
System.out.println("pattern was not specified");
return "";
} else {
pattern = (String)attributes.get("pattern");
}

// Create a DateFormatter for the pattern
DateFormat outputFormat = new SimpleDateFormat(pattern);

// Format the calendar
try {
Date date = originalFormat.parse(calendar.getTime());
return outputFormat.format(originalDate));
} catch (ParseException ex) {
ex.printStackTrace()
return "";
}
}
}


In faces-config.xml you would declare the converter like this:


<converter>
<converter-id>calendarConverter</converter-id>
<converter-class>com.blogspot.bigallan.converters.CalendarConverter</converter-class>
</converter>


We can now use the converter in a view:


<h:outputText value="#{myBean.calendarObject}">
<f:converter converterId="calendarConverter" />
<f:attribute name="pattern" value="d. MMMM yyyy" />
</h:outputText>


When the code is rendered in the browser you'll get the calendar converter to something like this 24. November 2008. So far so good. However, what if we didn't specify the date pattern as static text, but rather bind it to a value. This technique is efficient when you reuse the pattern in many places and want to keep the pattern in a central place. So say that we had a managed-bean called common with a method getDateFormat() : String that would provide the pattern. The code would look like this:


<h:outputText value="#{myBean.calendarObject}">
<f:converter converterId="calendarConverter" />
<f:attribute name="pattern" value="#{common.dateFormat}" />
</h:outputText>


When the code is rendered in the browser you'll get a blank response and see the following in the log, "pattern was not specified". The log statement is generated from out code above where we check for the attribute named "pattern". This is because of a requirement in the JSF 1.2 specification (JSR-252) that states (Section 9.4.2) that literal (static) text should be stored in the attribute map of the component and non-literal texts should be stored in the value expression map of the component. So to get the pattern from the value expression map we modify the getAsString method as follows:



public String getAsString(FacesContext ctx, UIComponent component, Object value) {

// Get the Calendar to convert
Calendar calendar = (Calendar) value;

String pattern = "";

// Obtain attributes specified along with the converter
Map<String, Object> attributes = component.getAttributes();

// Check if the pattern attribute was specified
if (!attributes.containsKey("pattern")) {

ValueExpression ve = component.getValueExpression("pattern");
if (ve == null) {
System.out.println("pattern was not specified");
return "";
} else {
pattern = (String) ve.getValue(ctx.getELContext());
}
} else {
pattern = attributes.get("pattern");
}

// Create a DateFormatter for the pattern
DateFormat outputFormat = new SimpleDateFormat(pattern);

// Format the calendar
try {
Date date = originalFormat.parse(calendar.getTime());
return outputFormat.format(originalDate));
} catch (ParseException ex) {
ex.printStackTrace()
return "";
}
}


The difference is that we now first check to see if there is a literal value specified. If not, we check if there is a value expression, and if there is no value expression either we will fail. If there is a value express we evaluate it and use it as our pattern.

Wednesday, 6 February 2008

Custom code folding in NetBeans

When you got large source files it can sometimes be helpful to create foldings for certain sections of your code. NetBeans got a nifty functionality for this using non-intrusive XML code (similar to Visual Studio).

To create a custom code folding section simply insert the following before the content to fold:


//<editor-fold defaultstate="collapsed" desc="My custom code folding">


and the following after the content to fold:


//</editor-fold>
.

So for example, if you had a JSF backing bean where you want to create a custom code folding for your properties, action listeners, and action handlers you could do as follows:


package backingbeans;

import javax.faces.model.*;
import javax.faces.event.*;

public class MyBackingBean {

private String prop1 = "";

public MyBackingBean() {
}

//<editor-fold defaultstate="collapsed" desc="Properties">
public String getProp1() {
return this.prop1;
}

public void setProp1(String prop1) {
this.prop1 = prop1;
}
//</editor-fold>


//<editor-fold defaultstate="collapsed" desc="Action listeners">
public void myFirstListener(ActionEvent event) {
... do something ...
}

public void mySecondListener(ActionEvent event) {
... do something else ...
}
//</editor-fold>

//<editor-fold defaultstate="collapsed" desc="Action handlers">
public String myFirstActionHandler() {
... do something ...
return "OUTCOME1";
}

public String mySecondActionHandler() {
... do something else ...
return "OUTCOME2";
}
//</editor-fold>
}


This will create three custom folders that are collapsed by default when the file is opened.

If you like this, I'd suggest setting up a coding template for inserting the XML code as it can otherwise be tricky to remember. This is done by following these steps:


  1. Click Tools -> Options

  2. Select "Editor" from the top options

  3. Select the "Code Templates" tab

  4. Select "Java" in the Language dropdown

  5. Click the "New" button

  6. Enter the shorthand for inserting the template, for example I use 'efold'

  7. Click the "OK" button

  8. The template has been created, now enter the following code into the Expanded Text textbox:

    //<editor-fold defaultstate="collapsed" desc="${cursor}">

    //</editor-fold>

  9. Click the "OK" button.



You can try out the template by opening a Java source file, place the cursor where you want to insert the folding and type efold followed by the tab key. It will now have inserted the complete editor-fold and place the cursor ready for you to enter a description for the folding.

Monday, 4 February 2008

Concatenating strings in JSF

To start the day off I though I'd share a quick tip using JSF. Say you have a list of messages:

quicktip.Messages:


ITEM_1=First item
ITEM_2=Second item
ITEM_3=Third item

Now, on your JSF page you would like to show one of these messages depending on the ID of the item to display. For example, you might have an list of beans containing items you'd like to display:

quicktip.Item

package quicktip;

public class Item {

/** Unique ID of the item. */
private int id;

/** Number of items. */
private int count;

public Item() {}

...usual getters and setters...

}


So, in your backing bean to the JSF page you have a method that constructs a DataModel containing items (I won't go into those details as it's not very exciting). For the sake of this example the signature of the method is public DataModel getItems();

Finally we get to the interesting bit, the actual JSF page.

... usual jsf stuff ...
<html>
<f:loadbundle basename="quicktip.Messages" var="msgs" />
<body>
<h:datatable value="#{backingBean.items}" var="item">
<h:column>
<c:set var="key" value="ITEM_#{item.id}" />
<h:outputtext value="#{msgs[key]}" />
</h:column>
<h:column>
<h:outputtext value="#{item.count}" />
</h:column>
</h:dataTable>
</body>
</html>


That's it. So, the real gist of the tip is that you can use the jstl tag to concatenating a string that you can re-use to fetch values from maps.