2012-01-25

Add Seam Report (JasperReport) to a JEE 6 Project - a simple example



For generating a pdf and printing some data, I decided to use JasperReports in my existing project. Because it is a Maven-based JEE 6 project, I wanted to give Seam Report a try. It allows to integrate different reporting tools like JasperReport, Pentaho or XDocReport. I use a simple Maven project from my other articel, you can download the project here.

Requirements(read here how to do this):

- you have installed Maven 3 or later and configured the JBoss Maven repository
- you have installed Eclipse with JBossTools
- you have installed the JBoss Applicationserver 7.0.2 and added the server runtime to Eclipse



You will need iReport to create the report, download it here.


Skip the following step, if you have already a JEE 6 project with CDI support.

1. Import example project



1.1 Extract the example project to a path at your harddisk.

1.2 Start Eclipse and import the project:

1.3 Choose File > Import > Maven > Existing Maven Projects and click next

1.4 Browse to the folder of the example project



1.5 Make sure the checkbox of the pom.xml is activated before you hit finish


2. Configure the project



Add this property to the pom.xml:


  3.1.0.Final



and the following dependencies:


  org.jboss.spec.javax.servlet
  jboss-servlet-api_3.0_spec
  provided


  org.jboss.spec.javax.faces
  jboss-jsf-api_2.0_spec
  provided


  org.jboss.seam.reports
  seam-reports-jasper
  ${seam-reports-version}
  
    
      dom4j
      dom4j
    
  



3. Add PDF generation



3.1 Create a package org.example.util in the source folder and a class MemberReport

package org.example.util;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletResponse;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

import org.example.data.MemberListProducer;
import org.jboss.seam.reports.Report;
import org.jboss.seam.reports.ReportCompiler;
import org.jboss.seam.reports.ReportDefinition;
import org.jboss.seam.reports.ReportRenderer;
import org.jboss.seam.reports.jasper.annotations.Jasper;
import org.jboss.seam.reports.output.PDF;
import org.jboss.solder.resourceLoader.Resource;

@Named
public class MemberReport {
 
    @Inject
    @Resource("memberReport.jrxml")
    InputStream sourceReport;

    @Inject
    @Jasper
    ReportCompiler compiler;

    @Jasper
    JRDataSource jasperDataSource;

    @Inject
    @Jasper
    @PDF
    ReportRenderer pdfRenderer;
    
    @Inject
    MemberListProducer memberListProducer;

    public ByteArrayOutputStream generateMemberReport() throws Exception {
    
        ReportDefinition report = compiler.compile(sourceReport);
        
        Map params = new HashMap();
        params.put("ReportTitle", "Member Report");
        
        Report reportInstance = report.fill(
          new JRBeanCollectionDataSource(memberListProducer.getMembers()), params);
         
        ByteArrayOutputStream os = new ByteArrayOutputStream(); 
        
        pdfRenderer.render(reportInstance, os);
        
        return os;
       
    }
    
 public void createPdf() throws Exception {

     byte[] pdfData = generateMemberReport().toByteArray();
     FacesContext facesContext = FacesContext.getCurrentInstance();
     ExternalContext externalContext = facesContext.getExternalContext();
     HttpServletResponse response = 
              (HttpServletResponse) externalContext.getResponse();

     response.reset(); 
     response.setContentType("application/pdf"); 
     response.setHeader("Content-disposition", 
                               "attachment; filename=\"memberReport.pdf\""); 

     OutputStream output = response.getOutputStream();
     output.write(pdfData);
     output.close();

     facesContext.responseComplete(); 
 }
}


3.2 In src/main/webapp/index.xhtml add the following lines between dataTable and define at the end of the file

  


3.3 Open iReport choose File > New.. in the menu and select Blank A4, click Open this Template



3.4 Name it "memberReport" and browse to the resource folder of the project, i.e. /Users/myUser/Documents/workspace/JEE6Project/src/main/resources



3.5 Add the fields name, email and phoneNumber to the report



3.6 Drag and drop the fields to the detail area of the report

3.7 Create a parameter and name it "ReportTitle", drag it to the title area of the report. It should look like this:



3.8 Save and open the report in Eclipse. In the second line change language="groovy" to language="java"

3.9 In Eclipse right click the pom.xml and choose Run As -> Maven install

3.9 You should find the file JEE6Project.war in the target folder, right click it and select "Mark as Deployable". Choose a JBoss 7 runtime environment

Open http://localhost:8080/JEE6Project and click Print all members, the generated PDF should look like this:



Download the final project

Versions of software used:

Install Maven, JBoss 7.0.2 and setup a JEE 6 project



1. Install JBoss 7.0.2



1.1 Download and extract JBoss 7.0.2

1.2 Linux only: in a command shell change to the JBoss directory(.../jboss-as-7.0.2.Final/bin) and make standalone.sh executable with: chmod 755 standalone.sh

1.3 Start JBoss in .../jboss-as-7.0.2.Final/bin with ./standalone.sh in Linux or standalone.bat in Windows. You shuold see something like:

16:20:24,569 INFO [org.jboss.as] (Controller Boot Thread) JBoss AS 7.0.2.Final "Arc" started in 1783ms - Started 93 of 148 services (55 services are passive or on-demand)

Open the URL http://localhost:8080/ in your browser. The welcome page of JBoss should be seen.


2. Setup Maven



Maven is used for building and managing Java-based projects. You will find more about installing Maven at maven.apache.org

2.1 Download Maven 3 or a later release and extract it to a path of your choise

2.2 Open another shell and set the enviroment variable M2_HOME pointing to your Maven directory, for example

within Linux:

In a command terminal, add the M2_HOME with export M2_HOME=/Users/myUser/Development/apache-maven-3.0.3 Also add it to your path: export PATH=$M2_HOME/bin:$PATH

within Windows:

Hit the WinKey+Pause, select "Advanced" M2_HOME=C:/myUser/Development/apache-maven-3.0.3 Add /Users/myUser/Development/apache-maven-3.0.3/bin to your user variable

2.3 In the command shell try maven -version, you should see something like: Apache Maven 3.0.3

2.4 Configure the JBoss repository(more details can be found at the JBoss-Wiki)

Add the following profil under in ../apache-maven-3.0.3/conf/settings.xml

    
       jboss-public-repository
       
          
             jboss-public-repository
             !false
          
       
       
          
             jboss-public-repository-group
             JBoss Public Maven Repository Group
             http://repository.jboss.org/nexus/content/groups/public
             
                true
                never
             
             
                false
                never
             
          
       
       
          
             jboss-public-repository-group
             JBoss Public Maven Repository Group
             http://repository.jboss.org/nexus/content/groups/public
             
                true
                never
             
             
                false
                never
             
          
       
    


3. Create a Maven JEE 6 project



3.1 In the command shell go to your favourite project folder, i.e. /Users/myUser/Documents/workspace

3.2 run: mvn archetype:generate -DgroupId=org.example -DartifactId=JEE6Project -DpackageName=org. -Dversion=0.0.1-SNAPSHOT -Dfilter=jboss-javaee6-webapp-archetype

3.3 Type 1 and hit return. Hit it again until Maven has finished

3.4 You should see a new folder "JEE6Project".

3.5 In your project directory (.../JEE6Project/ where the pom.xml is stored) run: mvn clean install

3.6 Now copy the new war file to the JBoss deploy directory, i.e. cp .../JEE6Project/target/JEE6Project.war ~/Documents/workspace/JEE6Project (This can also be done with Maven, but needs a bit more configuration)

In your browser type http://localhost/JEE6Project/, the final result should look like this:



4. Create a JEE6Project with Eclipse



At the JBoss website you can find a good documentation and also a video tutorial how to create a JEE 6 project. Before you only have to install Eclipse and JBossTools.

4.1 Start Eclipse(I use Eclipse Indigo Service Release 1)

4.2 In the menu choose Help > Install new Software > Add...

4.3 Enter a name like "JBossTools" and add the URL http://download.jboss.org/jbosstools/updates/development/indigo/. Look at the JBossTools documentation for the actual URL.

4.4 Select everything and hit next

4.5 Accept the licences and go on till the installer ends

4.6 Follow the video tutorial here

2012-01-23

JBoss 7.0.2 and Seam Report throws Exception MSC00001: Failed to start service jboss.persistenceunit

I added Seam Report(with JasperReports) to my maven project and got this exception:
 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-4) MSC00001: Failed to start service jboss.persistenceunit."test.
war#testPU": org.jboss.msc.service.StartException in service jboss.persistenceunit.""test.war#testPU": Failed to start service
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1780) [jboss-msc-1.0.1.GA.jar:1.0.1.GA]
   at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [:1.6.0_27]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [:1.6.0_27]
   at java.lang.Thread.run(Thread.java:662) [:1.6.0_27]
Caused by: java.lang.ClassCastException: org.dom4j.DocumentFactory cannot be cast to org.dom4j.DocumentFactory
    at org.dom4j.DocumentFactory.getInstance(DocumentFactory.java:97)
   at org.dom4j.DocumentHelper.getDocumentFactory(DocumentHelper.java:36)
   at org.dom4j.DocumentHelper.createDocument(DocumentHelper.java:41)
    at org.hibernate.envers.configuration.RevisionInfoConfiguration.generateDefaultRevisionInfoXmlMapping(RevisionInfoConfiguration.java:86)
   at org.hibernate.envers.configuration.RevisionInfoConfiguration.configure(RevisionInfoConfiguration.java:322)
    at org.hibernate.envers.configuration.AuditConfiguration.(AuditConfiguration.java:94)
   at org.hibernate.envers.configuration.AuditConfiguration.getFor(AuditConfiguration.java:134)
   at org.hibernate.envers.event.EnversIntegrator.integrate(EnversIntegrator.java:63)
    at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:294)
   at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1722)
   at org.hibernate.ejb.EntityManagerFactoryImpl.(EntityManagerFactoryImpl.java:76)
    at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:899)
   at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:884)
   at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:73)
    at org.jboss.as.jpa.service.PersistenceUnitService.createContainerEntityManagerFactory(PersistenceUnitService.java:143)
   at org.jboss.as.jpa.service.PersistenceUnitService.start(PersistenceUnitService.java:77)
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:1824) [jboss-msc-1.0.1.GA.jar:1.0.1.GA]
   at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1759) [jboss-msc-1.0.1.GA.jar:1.0.1.GA]
    ... 3 more
First I didn't noticed that, because the error only occured with a restart of JBoss and not while deploying the archive. The reason of this error is, that the JasperReports dependency has its own dom4j-1.6.1.jar. This file is copied to the WEB-INF/lib directory. I found different solutions, but no one was really working. Finally I excluded the dom4j from the dependency:

  org.jboss.seam.reports
  seam-reports-jasper
  ${seam-reports-version}
  
  
    
      dom4j
      dom4j
    
  

This way I dont have the problem anymore. I used: