Enterprise Java

JasperReports JSF Plugin Use Cases Series

This is the entry point of an article series in which I will try to cover some of the use cases of JasperReport JSF Plugin, a tool created to easily integrate business reports designed for JasperReports in JSF applications. All the examples described in this series are available from the JasperReports JSF Plugin web site, at the samples section and will be part of the same business application: An online book store.

The series will go through the steps needed to build the previous mentioned web application. I will try to keep the articles as neat, self-contained and complete as possible but I will deliberately omit some parts not specifically related with none of the main technologies exposed here. This way each article will go straight to the point and will be less verbose enabling easier understanding of main actors and their roles.

Before getting deep into the material in which I will explain the different scenarios for JasperReports JSF Plugin we need to setup the web application project that will be the starting point for the further use cases. The main tools used in this series to work on that project are as follows:

  • JasperReports 4.5.1 : the reporting engine.
  • iReport 4.5.1 : the visual report designer
  • Java Server Faces 1.2 & Facelets 1.1.1 : the web framework for my application (notice that this can be easily migrated into JSF 2.x).
  • JasperReports JSF Plugin 1.0 : the integration bridge between the reporting engine and the web framework.
  • Apache Derby 10.8.2.2 : database that will hold the information that we need.
  • Apache Tomcat 6.0.35: the application server that I will use to deploy and test the application.

The data to be shown by each specific report will come from a simple database with a few tables that will hold the information we need. The main entities that I will be using to compound the domain model are, basically: books, customers, orders and order lines.

Contents

Project Setup

The approach I will follow is to create a new web-based project that will use that database model. I will use Maven to configure and manage the dependencies that I will use since I’m pretty used to it and it will avoid me to grab all the jar files independently and configure them in my code base by hand. Any other can use the tool of his/her preference (Ant, Gradle, IDE-based, etc.).

A good example for doing this with Maven is the “simple-webapp” archetype sample from the Maven Book. I will post here the command line sentence I used to generate my project structure using that archetype:

mvn archetype:create -DgroupId=net.sf.jasperreports.jsf.sample
-DartifactId=jrjsf-usecases
-Dpackage=net.sf.jasperreports.jsf.sample.usecases
-Dversion=1.0-SNAPSHOT
-DarchetypeArtifactId=maven-archetype-webapp
-DarchetypeGroupId=org.apache.maven.archetypes
-DarchetypeVersion=1.0

This will generate a Maven project in a folder with name jrjsf-usecases and with the following initial values:

  • groupId: net.sf.jasperreports.jsf.sample
  • artifactId: jrjsf-usecases
  • version: 1.0-SNAPSHOT
  • package: net.sf.jasperreports.jsf.sample.usecases

Now the pom.xml file needs to be modified a bit to hold the dependencies needed for our project. The main changes I will do will consist on adding support for Java 1.5 (and higher) and the dependencies to the items listed at the beginning of the article.

To be able to use generics and other fancy features added to Java after the release of Java 5 we need to configure the maven-compiler-plugin so the Java compiler can recognise that we want support for those features:

<project>
    ...
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <groupId>org.apache.maven.plugins</groupId>
                <configuration>
                    <source>1.5</source>
                    <target>1.5</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

And now let’s add the dependencies we need to implement our application:

<project>
    ...
    <dependencies>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.4</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.el</groupId>
            <artifactId>el-api</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-api</artifactId>
            <version>1.2_14</version>
        </dependency>
        <dependency>
            <groupId>javax.faces</groupId>
            <artifactId>jsf-impl</artifactId>
            <version>1.2_14</version>
        </dependency>
        <dependency>
            <groupId>com.sun.facelets</groupId>
            <artifactId>jsf-facelets</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>net.sf.jasperreports</groupId>
            <artifactId>jasperreports</artifactId>
            <version>4.5.1</version>
        </dependency>
        <dependency>
            <groupId>net.sf.jasperreports.jsf</groupId>
            <artifactId>jasperreports-jsf</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.derby</groupId>
            <artifactId>derbyclient</artifactId>
            <version>10.8.2.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

In this project we will be using a container-managed data source accessible through JNDI. This kind of configuration is dependant of the type of application server that we are using. Since I’m using Tomcat as my application server, I need to add a context.xml file to our project under the folder src/main/webapp/META-INF to tell it how to get access to that database and the type of resource I want:

<Context path='/jrjsf-usecases' reloadable='true'>

 <Resource name='jdbc/BookStoreDB' auth='Container' type='javax.sql.DataSource'
  maxActive='100' maxIdle='30' maxWait='10000'
  username='app' password='' driverClassName='org.apache.derby.jdbc.ClientDriver'
  url='jdbc:derby://localhost:1527/bookstoredb;create=true'
 />

</Context>

Configuring iReport

We need to configure iReport to make it able to connect to our database so let’s launch the iReport design tool and configure it to have it ready for the design work. iReport doesn’t bring support to the Apache Derby database out-of-the-box, we need to add the libraries to its classpath and configure the Derby JDBC driver by hand. This exercise will teach us to configure the tool to support any other database by the way.

First of all, download the Apache Derby database from its website and install it (decompress the zip file) in a folder of your choice in your local machine, if you haven’t done it yet. Then open iReport’s preferences/options window and select the classpath tab:

I will add the Derby’s lib folder into the iReport classpath. To do so click on “Add Folder” button and browse your filesystem until you get to the lib folder inside the Apache Derby installation:

Once done, click the OK button at preferences window and now the Apache Derby client classes should be available in iReport. At this moment we are ready to configure the Apache Derby datasource in iReport which is going to be used by our reports. To add a new datasource we can start from either the iReport welcome page and clicking on “Step 1: Create a database connection …” button or by clicking on the “Report datasources” button at the tool bar and then clicking on the “Add” button. Either way we will get to a window like the following:

The Apache Derby datasource needs to be completely configured by hand in iReport so choose “Database JDBC connection” in the list from previous window, click on “Next >” and fill in the values for the JDBC driver in the next window:

The values for the fields are as follows:

  • Name: BookStoreDB
  • JDBC Driver: org.apache.derby.jdbc.ClientDriver
  • JDBC URL: jdbc:derby://localhost:1527/bookstoredb
  • Username: app
  • Password: <empty>

Now, before continuing, make sure that your Apache Derby instance is running to allow connections against it and click on the “Test” button to check everything is fine.

The Domain Model

Let’s say that our project is configured and ready to start to work on it (we have a basic project folder structure and all the basic dependencies are in our classpath, and iReport is able to connect to our database) so let’s start with a bit of code. My first step in this area will be to create a SQL file (bookstore.create.sql) to initialize the domain model I’ve been talking about in the Introduction paragraph of this series. Copy the text below this paragraph and paste it into a file inside your project folder structure so you can use it later:

create table book (
    book_id int generated by default as identity primary key,
    title varchar(50) not null,
    author varchar(50) not null,
    published_year varchar(4) not null,
    genre varchar(20) not null,
    price numeric not null
);

create table customer (
    customer_id int generated by default as identity primary key,
    name varchar(250) not null
);

create table purchase_order (
    order_id int generated by default as identity primary key,
    customer_id int not null,
    created_date date not null,

    constraint customer_fk foreign key (customer_id) references customer(customer_id)
);

create table purchase_order_line (
    order_line_id int generated by default as identity primary key,
    order_id int not null,
    book_id int not null,
    item_count int not null,

    constraint order_fk foreign key (order_id) references purchase_order(order_id),
    constraint book_fk foreign key (book_id) references book(book_id)
);

This is just the backend part of my domain model, in my application I need to represent those entities as Java classes as well. So, to have this domain model complete my next step will be to write the Java classes that I need to represent the previous defined domain model inside my Java application. Now it’s time to take a look to previous model, we have 4 different entities so we will need 4 different classes inside our Java application to comply with that model:

Book

public class Book {

    private Long id;

    private String title;

    private String author;

    private String publishedYear;

    private String genre;

    private double price;

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getGenre() {
        return genre;
    }

    public void setGenre(String genre) {
        this.genre = genre;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public String getPublishedYear() {
        return publishedYear;
    }

    public void setPublishedYear(String publishedYear) {
        this.publishedYear = publishedYear;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

}

Customer

public class Customer {

    private Long id;

    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Order

public class Order {

    private Long id;

    private Customer customer;

    private Date createdDate;

    private List lines = new ArrayList();

    public Date getCreatedDate() {
        return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
        this.createdDate = createdDate;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public List getLines() {
        return lines;
    }

    public void setLines(List lines) {
        this.lines = lines;
    }

}

OrderLine

public class OrderLine {

    private Long id;

    private Order order;

    private Book book;

    private int itemCount;

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public int getItemCount() {
        return itemCount;
    }

    public void setItemCount(int itemCount) {
        this.itemCount = itemCount;
    }

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }

}

Now, use the tool of your choice to connect to your database and execute the bookstoredb.create.sql file to create the table structure.

Conclusion

I’m trying to keep the code as simple and clean as possible. The Java classes listed in the previous section can be mapped to our relational database using ORM tools such as Hibernate, iBATIS, Ebean, etc. I leave the choice of the Object Relational Mapping layer to the reader as there are many choices and none of them will affect the way we integrate our report with the web framework.

Our web application should contain other classes to compose its architecture as DAO’s and business facades and view controllers. However, adding all of them in this article is completely out of scope for the same reason that I am not adding any ORM information that may help to link the model classes to the database tables. There are a lot of IoC containers out there nowadays (Spring Framework, Weld, Seam, etc) and what really matters in this series is to demonstrate the usage of the JasperReports JSF Plugin. (View controllers will be listed in its specific article as they are part of each specific use case).

And this is all we need to start working in the different examples of this nifty tool. During the next weeks new articles will be published under the JasperReports JSF Plugin category giving detailed examples that demonstrate how implement the most common use cases. Hope you enjoy them, any comments are welcome.

Reference: JasperReports JSF Plugin Use Cases Series from our JCG partner Alonso Dominguez at the Code Nibbles blog.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button