Tuesday, October 28, 2008

Multiple Struts Resource Bundles

The process of adding multiple resource bundles to a single Struts 1.35 webapp can be a little cryptic. This should help clear things up.

struts-config:
The first thing you need to do is to define the resource bundles in your struts-config.xml file. The typical struts-config file contains a line that defines the default resource bundle:

<message-resources parameter="resources.application"/>

To add an additional bundle we need to assign it a key as well as a parameter like so:

<message-resources key="registration" parameter="resources.registration"/>

Our complete struts-config now contains the following lines:

<message-resources parameter="resources.application"/>
<message-resources key="registration" parameter="resources.registration"/>

Properties Files:
Create the property files in the /WEB-INF/classes/resources directory with a .properties extention. Now you can add the properties your application will use in each file:

application.properties
site.title=Site Title

registration.properties
username=Your Username

JSP:
Now you can use the properties from either the default bundle or the registration bundle by specifying the bundle (from the key in the struts-config).

<bean:message bundle="registration" key="subhead.note" />
<bean:message key="errors.general" />

You can add more resource bundles by defining them in the struts-config file with a unique key.

Monday, October 6, 2008

Struts 2 Multibox

I've had a lot of experience with Struts 1.x and decided it was time to move on to the newer Struts 2 framework. I have found much of the documentaion helpful, but there was one thing that I got hung up on. That thing was: what happened to the tag? It was obvious to me that the functionality had to be available in Struts 2, but where was it?

I had limited success with the tag, but it would always fail validation if none of the options were selected. This made no sense to me since selection one or more of the checkboxes would return exactly what I expected, an array of Longs. In my action I had my results defined as:

private Long[] valueArray;

The problem was that the Interceptor that the conversion interceptor was generating an error when no values were selected. The reason this was happening was due to the fact that instead of returning an empty array or even null, Struts now returns "false" by default. This meant that valueArray[0] == "false" which obviously cannot be converted to a number.

Here's how I overcame the multibox functionality:

JSP Code:

<s:iterator status="rowStatus" value="orderList">
<tr>
<td>
<s:checkbox fieldvalue="%{orderId}" name="valueArray">
</td>
<td>
<s:property value="orderName">
</td>
</tr>
</s:iterator>

Action Code:

private List valueArray;

public String execute() throws Exception
{
long[] longArray = asLongArraySafe(valueArray);

// Do something with the longArray.

}

// This method will create an array that contains only the numeric values.
public long[] asIntArraySafe(List list)
{
long[] results = new long[0];
ArrayList parsedValueList = new ArrayList();
if(list != null && list.size() > 0)
{
for(String valueString : list)
{
try
{
parsedValueList.add(new Long(valueString));
}catch(Exception e){}
}

results = new long[parsedValueList.size()];
int x = 0;
for(Long value : parsedValueList)
{
results[x++] = value.longValue();
}
}
return results;
}

Sunday, October 5, 2008

Jasper Report Batch Printing for Multiple Page Reports

One of the things I've been trying to do for a few days now is to download multiple, dynamically generated, PDF reports as a single file. My problem was that each of the pages in this report were different and needed to use not only different data, but a different report template as well.

I looked at Jasper Reports, the defacto standard, but it seemed like I would only be able to create a multiple page PDF document that shared the same template. What's worse is that Jsaper Reports enforces a maximum height of 738 px in the detail section of the report. This meant I couldn't use page breaks to give each page its own unique look and feel.

After a little more reading, I discovered that Jasper Reports can generate PDF reports in "batch mode". Batch mode allows you to concatenate several reports together into a single File or OutputStream.

To use batch mode you must add your List of JasperPrint objects to the
JRExporterParameter.JASPER_PRINT_LIST parameter of the exporter.

Example:
ArrayList jasperPrintList = [Your logic for creating the list]

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

JRPdfExporter exporter = new JRPdfExporter();

exporter.setParameter(JRExporterParameter.JASPER_PRINT_LIST, jasperPrintList);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, outputStream);

exporter.exportReport();

inputStreamForStruts2 = new ByteArrayInputStream(outputStream.toByteArray());