Collections of web application techniques

Friday, July 24, 2009

Using JasperReports in JSF Applications

JasperReports is a reporting tool that can be used to generate reports in multiple formats such as PDF for printing and CSV for manipulation in a spreadsheet tool. This blog describes how you can integrate a JapserReport file (.jrxml) into a JSF-based application.

Although the jrxml template is just a text file, it is easier to use a tool such as iReport. iReport is good for general layout and can save you from tedious work but it is not perfect. Occasionally it is better to edit the xml file directly. GVim is an excellent text editor if you have a Linux background but any other text editor will do the job.

The jrxml file should be copy into a directory readable by the class loader. I put mine in /WEB-INF/reports. You can use the ReportGenerator class included to generate the desired report.

Typically a report is generated when a user clicks a button or a link which invoke an action listener. The action listener method then calls the ReportGenerator’s printReport() and a report in the desired format (HTML, PDF, CSV, EXEL) is returned to the user. PDF format with JasperReports is excellent as it uses absolute positioning. However HTML and EXEL are not very good as the outcomes can be surprisingly different. I recommend that you provide PDF for printing and CSV for data manipulations to the users as those two formats seem to work best.

Below is an example on the variation that a report should be opened on a new window after user fill out the criteria on a form. To make it a little more user friendly, error checks were performed on the back end and will be displayed on the same page. Therefore, we can’t just set the target to _blank to force the browser to open a new window whenever an action is submitted.

In your form, you might have a button like this:

<h:commandButton value="Generate" action="#{report.submit}"/>


Your action listener then validates the inputs and if there is any error, it will be sent back to the same page:

public final String submit() {
if (!criteria.isValid()) {
facesMessages.add(Severity.ERROR, "Some error messages"
return ERROR;
}

return NEXT;
}


When everything is well, we can pass control to the report generator. Wait! What if users had some errors previously which where displayed on the form? Clearing them would be good.


Here is an example that works for JBoss Seam (if you are not, you definitely need to check it out). The trick is to reload the form and open the new window for the report. The navigtion rule below specifies that the view will be report.jsp.


<navigation from-action="#{report.submit}">
<rule if-outcome="next">
<redirect view-id="/app/report/report.jsp"/>
</rule>
</navigation>


Below is the content for report.jsp. It refreshes the main form (reportForm.jsp) and opens display.jsp.

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script language="JavaScript">
function displayReport() {
reportUrl = "display.x";
newWin = window.open(reportUrl,"_blank",
"location=0,resizable=1,status=1,scrollbars=1,menubar=1,toolbar=0");
newWin.focus();

document.getElementById("report:location").click();
}
</script>
</head>
<body onload='displayReport()'>
<h:form id="report">
<s:button id="location" style="display:none" view="/app/report/reportForm.jsp" value="return" propagation="join">
</s:button>
</h:form>
</body>
</html>

</ui:composition>


Below is the content for display.jsp:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:s="http://jboss.com/products/seam/taglib"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:rich="http://richfaces.org/rich"
>

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Expires" content="-1"/>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script language="JavaScript">
function displayReport() {
document.getElementById("report:location").click();
}
</script>
</head>
<body onload="document.body.style.cursor='wait'; displayReport();">
<h:form id="report" >
<div style="width:90%; padding:5px; margin:40px; border: 1px solid #FFCC00; background-color: #F0F8FF;">
<h:outputText value="Please wait..."/>
<h:commandButton id="location" style="display:none" action="#{report.display}"/>
</div>
</h:form>
</body>
<header>
<meta http-equiv="Expires" content="-1"/>
</header>
</html>
</ui:composition>


Displaying a message with some progress indicator would be even better on this last page. To do that, you can specify a refresh rate in this last page to get the progress. This is much easier than create a thread on the server end.

<meta http-equiv="refresh" content="1"/>

And here is the method display invoking the report generator:

public final String display() {
ReportPreparer prep = new ReportPrepFactory().getPreparer(criteria);

String template = "sample"; // Suppose your jrxml file is sample.jrxml

Map p = new HashMap(); // if your report has parameters, they should be set here

ReportGenerator gen = new ReportGenerator();
if (gen.printReport(
"P", // P for PDF
p,
new StringBuffer("/WEB-INF/reports/").append(template)
.append(".jrxml").toString(),
template)) {
return NEXT;
}

return ERROR;
}


This is the code to generate report:

Wednesday, July 22, 2009

A Comparison of Java Webapp Report Tools

I recently completed the conversion from Crystal report to Jasper Report. The Crystal reports were causing me too much pain when using in my Java web application. This is not to say that Crystal is bad, actually using Crystal is somewhat better than iReport (a tool to generate Jasper Report). The only complain I have against it is that coming from Java, I just don’t like its expression language and deploying Crystal reports on Business Object to server reports to end users is a nightmare.

Crystal Jasper Report Birt
Pros
  • Feature rich
  • Non programmers can do it (Java is not required except for the parameter passing but we already figured it out)
  • Can overlay elements on background pictures when designing reports.
  • More people are familiar with this tool

  • Free – open source
  • Absolute coordinates
  • Java syntax out of the box
  • iReport is a Swing (newer version is based on NetBeans platform) application to design reports
  • Reports data can be provided from application via Hibernate O/R or just from report’s SQL
  • Re-deployment can be just as simple as dropping a file into live application (no down time)

  • Free – open source
  • Newer than Jasper with slicker designer interface. Developers especially those familiar with Eclipse will feel at home
  • Can embed reports in applications or deploy on BIRT report server as Crystal
  • Probably can be used in a lot of cases but I could not got it to work with a complex report with multiple different backgrounds.
  • Cons
  • Crystal’s own language or VB for function expressions
  • DB fine grained access forced us to use stored procedure. Mistakes can be easily made.
  • Needs Business Object Server. Reports cannot be embedded in the application
  • Potential security issues
  • Harder to deploy. Easier to make mistakes on deployment. Bugs have been written due to deployment issues
  • Costs money

  • Documentation for iReport costs money (should be much, much less than Crystal though)
  • No multiple headers or detail sections
  • Can’t overlay elements on pictures on iReport. Placement is a trial and error process
  • Non Java programmer might not like it.
  • iReport is not error free
  • No substitute for “Underlay Following Sections” feature in Crystal

  • HTML/CSS layout. Viewing in different formats produced drastically different results
  • Can’t overlay data on images. Features on images seem less robust than iReport
  • Non programmers might not like it because they have to deal with Eclipse IDE
  • I didn’t figure out the deployment part yet but that shouldn’t be a show stopper
  • Friday, July 10, 2009

    Leveraging ASP Window Authentication in Java Web Applications


    For web applications running inside a corporate intranet where users are maintained by a Microsoft Windows Active Directory, a seamless authentication method is often desired. If your web application consists of only Microsoft technologies, then just surf on Microsoft web site and follow their instructions.


    Authentication in ASP is extremely simple; all you need to secure your asp page is to configure IIS to set the directory where your page resides to use Integrated Windows Authentication. Then in your ASP page, you just need to add this line:


    userId = request.ServerVariables("LOGON_USER")


    That’s all! You’ll get the NT login ID that identifies who the user is and then you can move on to authorization. All the work is done for you behind the scence.


    But if you’re a Java guy who also wants to give users a seamless authentication experience, you’ll have to look elsewhere.


    JCIFS is an answer - almost. I’ve used it and my users got authenticated just fine for most of the time. Occasionally, my users could not be authenticated due to some changes in the network, their environments, whatever… In my experience, the one liner in ASP worked when JCIFS failed. As an application developer who would rather concentrate on developing front end applications, I’ve given up on getting the right network IP addresses to configure the NtlmHttpFilter for JCIFS. In fact, when users could not be authenticated, nobody seems to know what happens. Trying to understand the JCIFS source code is just fruitless when dealing with frustrated users. So here is a way to leverage it: let Microsoft technologies say with Microsoft technologies. They can be a black box - a reliable black box. Who cares as long as it works?