Sunday, December 9, 2012

Using Jasper Report In ADF Application (Step-by-Step)

In my previous post  http://sameh-nassar.blogspot.com/2009/10/using-jasper-reports-with-jdeveloper.html I explain how to use Jasper Report but because of many people send me many requests for explain this topic in more detail so I will explain it in step by step.

our example will make application with one screen this screen has a table of employees you should select an employee and send the selected employee id to jasper report to print the selected employee data.

Before we begin be sure of:

1- You download iReport-4.0.1 (you can get it from http://sourceforge.net/projects/ireport/files/iReport/iReport-4.0.1/) I download iReport-4.0.1-windows-installer.exe.

2- You have database has hr schema.

3- Setup JDeveloper 11g (any release).

Now we can begin ......

Step 1:

Setup iReport-4.0.1
Step 2:
Open JDeveloper and make new ADF Application (name it for example JasperApplication)

Step 3:

Connect your application to your database HR Schema by right click in your Model application ---> new ---> ADF Business Components ---> Business Components From Table
Add your connection and test the connection

Add one Entity Objects (Employees)
Add one Updatable View Objects
Then press finish, your application should be like this
Step 4:
Create new jspx page (name it for example employees.jspx)
In your ViewController project right click on Web Content folder then new --->JSF ---> JSF Page

From the Data Controls drag EmployeesView1 to your page as an ADF Read-only Table


From Row Selection Select Single Row
Add a button above a table (text it for example Run Report) and its action point to a method in a back bean (for example Back bean name is JasperBean.java)


To get the selected employee id:
    DCIteratorBinding empIter = (DCIteratorBinding) getBindings().get("EmployeesView1Iterator");
    String empId = empIter.getCurrentRow().getAttribute("EmployeeId").toString();

where EmployeesView1Iterator is the iterator name in the page definition and EmployeeId is the attribute name in the EmployeesView.

now we should pass the selected employee Id to jasper report so, you should make a map and set the parameter like
    Map m = new HashMap();
    m.put("employeeId", empId);// employeeId is a jasper parameter name

then you should call the jasper report like this method
 runReport("empReport.jasper", m);

where runReport is the method take jasper report name (empReport.jasper) and the map which hold the parameter

write this code in your JasperBean.java

--------------------------------------------------------------------------------------------------------------
  public BindingContainer getBindings()
  {
    return BindingContext.getCurrent().getCurrentBindingsEntry();
  }
  public Connection getDataSourceConnection(String dataSourceName)
      throws Exception
    {
      Context ctx = new InitialContext();
      DataSource ds = (DataSource)ctx.lookup(dataSourceName);
      return ds.getConnection();
    }
 
  private Connection getConnection() throws Exception
  {
    return getDataSourceConnection("hrDS");// use datasourse in your application
  }
 
  public  ServletContext getContext()
    {
      return (ServletContext)getFacesContext().getExternalContext().getContext();
    }
  public  HttpServletResponse getResponse()
    {
      return (HttpServletResponse)getFacesContext().getExternalContext().getResponse();
    }
  public static FacesContext getFacesContext()
    {
      return FacesContext.getCurrentInstance();
    }
  public void runReport(String repPath, java.util.Map param) throws Exception
  {
    Connection conn = null;
    try
    {
      HttpServletResponse response = getResponse();
      ServletOutputStream out = response.getOutputStream();
      response.setHeader("Cache-Control", "max-age=0");
      response.setContentType("application/pdf");
      ServletContext context = getContext();
      InputStream fs = context.getResourceAsStream("/reports/" + repPath);//we will put the report under folder "reports" under Web Content
      JasperReport template = (JasperReport) JRLoader.loadObject(fs);
      template.setWhenNoDataType(WhenNoDataTypeEnum.ALL_SECTIONS_NO_DETAIL);
      conn = getConnection();
      JasperPrint print = JasperFillManager.fillReport(template, param, conn);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      JasperExportManager.exportReportToPdfStream(print, baos);
      out.write(baos.toByteArray());
      out.flush();
      out.close();
      FacesContext.getCurrentInstance().responseComplete();
    }
    catch (Exception jex)
    {
      jex.printStackTrace();
    }
    finally
    {   
      close(conn);
    }
  }
 
  public void close(Connection con)
   {
     if (con != null)
     {
       try
       {
         con.close();
       }
       catch (Exception e)
       {
       }
     }
   }
--------------------------------------------------------------------------------------------------------

After you write this code you will find Jasper library missing

to get jasper libraries goto the folder which you setup iReport for example in this path
C:\Program Files (x86)\Jaspersoft\iReport-4.0.1\ireport\modules\ext
and get these libraries:
1- iText-2.1.7.jar
2- jasperreports-4.0.1.jar
3- jasperreports-fonts-4.0.1.jar

add this libraries to your ViewController project ---> Right click on the project ---> Project Properties--->Libraries And Classpath ---> Add JAR/Directory

Now your code should have no error

Now my Back bean code is :
----------------------------------------------------------------------------------------------------------------------
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.type.WhenNoDataTypeEnum;
import net.sf.jasperreports.engine.util.JRLoader;
import oracle.adf.model.BindingContext;
import oracle.adf.model.binding.DCIteratorBinding;
import oracle.binding.BindingContainer;

public class JasperBean
{
  public JasperBean()
  {
  }

  public String runReportAction()
  {
    DCIteratorBinding empIter = (DCIteratorBinding) getBindings().get("EmployeesView1Iterator");
    String empId = empIter.getCurrentRow().getAttribute("EmployeeId").toString();
    Map m = new HashMap();
    m.put("employeeId", empId);// where employeeId is a jasper report parameter
    try
    {
      runReport("empReport.jasper", m);
    }
    catch (Exception e)
    {
    }
    return null;
  }

  public BindingContainer getBindings()
  {
    return BindingContext.getCurrent().getCurrentBindingsEntry();
  }
 
  public Connection getDataSourceConnection(String dataSourceName)
      throws Exception
    {
      Context ctx = new InitialContext();
      DataSource ds = (DataSource)ctx.lookup(dataSourceName);
      return ds.getConnection();
    }
 
  private Connection getConnection() throws Exception
  {
    return getDataSourceConnection("hrDS");// datasource name should be defined in weblogic
  }
 
  public  ServletContext getContext()
    {
      return (ServletContext)getFacesContext().getExternalContext().getContext();
    }
  public  HttpServletResponse getResponse()
    {
      return (HttpServletResponse)getFacesContext().getExternalContext().getResponse();
    }
  public static FacesContext getFacesContext()
    {
      return FacesContext.getCurrentInstance();
    }
  public void runReport(String repPath, java.util.Map param) throws Exception
  {
    Connection conn = null;
    try
    {
      HttpServletResponse response = getResponse();
      ServletOutputStream out = response.getOutputStream();
      response.setHeader("Cache-Control", "max-age=0");
      response.setContentType("application/pdf");
      ServletContext context = getContext();
      InputStream fs = context.getResourceAsStream("/reports/" + repPath);
      JasperReport template = (JasperReport) JRLoader.loadObject(fs);
      template.setWhenNoDataType(WhenNoDataTypeEnum.ALL_SECTIONS_NO_DETAIL);
      conn = getConnection();
      JasperPrint print = JasperFillManager.fillReport(template, param, conn);
      ByteArrayOutputStream baos = new ByteArrayOutputStream();
      JasperExportManager.exportReportToPdfStream(print, baos);
      out.write(baos.toByteArray());
      out.flush();
      out.close();
      FacesContext.getCurrentInstance().responseComplete();
    }
    catch (Exception jex)
    {
      jex.printStackTrace();
    }
    finally
    {   
      close(conn);
    }
  }
 
  public void close(Connection con)
   {
     if (con != null)
     {
       try
       {
         con.close();
       }
       catch (Exception e)
       {
       }
     }
   }
}
--------------------------------------------------------------------------------------------------------------------------
Now depending on my previous code we should make a report the name of this report should be "empReport" and has one parameter "employeeId"

Step 5:

Open iReport and make a connection to hr database but first ..... iReport has not oracle database driver so you use oracle database you should first add a ojdbc jar file to the classpath of iReport.

you can get ojdbc jar file in your middleware home like:
C:\Oracle\Middleware\wlserver_10.3\server\lib and search for ojdbc6.jar

In iReport goto Tools---> Options ---> Classpath and add ojdbc6.jar
Now make a new connection to hr schema
Now from File ---> New and make new Report
Choose any template or make it blank then press "Launch Report Wizard"

Write report name "empReport" and under your web content folder in ViewController project make new folder "reports" and save the report on this path


Press on Design query button and select your schema then drag Employees table
then press Ok you will find the report query will generated then press Next and shuttle the field you want to displayed in your report
Then press next then finish. You will find you report generated.
Goto the report query as shown:

and make new Parameter "employeeId"
add where clause to the query like:
WHERE EMPLOYEES."EMPLOYEE_ID"=to_number($P{employeeId})

Now you can preview your report by pressing on "Preview" button and enter for example employeeId = 200


Now compile your report to generate .jasper file in your application
If you goto your application you should something like this:
before you run be sure of two things:
1- any picture you use in jasper should be in the class path
2- You should define datasource in your weblogic "as we write in the code datasource is hrDS"


for how you can define data source in weblogic try this http://www.mediafire.com/view/?g7odbc06rpad1aa

Step 6:
run your application and select any employee then press on "Run Report" button
for example select employee Id= 104 then run report



you can download the application from this link JasperApplication

Good luck :)



23 comments:

  1. Very Nice and easy to understand. thanks for sharing such a nice content.

    ReplyDelete
  2. هذا هو الإبداع الحقيقي في عرض المعلومة
    جزاك الله عنا كل خير

    ReplyDelete
  3. Brother Sameh,

    can you please tell me that I want to develop an Oracle based large scale web application and want to use some reporting it it. Jasper reporting tool is appropriate for the said reporting? I mean, the features grouping, controls etc (like we use in .Net Crystal Report) are available?

    Please reply me here(or if you can personally in my address rsiddiqui@abacusoft.com)

    Jazak ALLAH

    ReplyDelete
    Replies
    1. Hi Rashid,

      I don't work with Crystal Report before but Jasper has grouping, controls, graphs, calling java methods feature and sub-report. We make very large scale applications with complex report using jasper.

      Regards,

      Delete
  4. The Report Integration Framework goes far beyond this:
    http://whitemagicsoftware.com/software/java/rif/

    Read Chapter 15 (free) to see a generic way to integrate JasperReports with ADF: http://whitemagicsoftware.com/books/indispensable/

    The idea is that you can decouple any report framework from the ADF application. The last thing you want to do is couple Oracle Reports, JasperReports, BIRT, or CrystalReports to your application when you don’t need to.

    The Report Integration Framework provides a pluggable system where you can swap out one report engine for another, and not one line of code in the ADF application needs to change.

    ReplyDelete
  5. Dear eng.sameh
    I Follow the steps but the program generate this error
    javax.naming.NameNotFoundException: Unable to resolve 'hrDS'. Resolved ''; remaining name 'hrDS'
    please if u can fixed this issue i'll appreciate

    regards

    ReplyDelete
    Replies
    1. Dear sief,
      this is not an issue, you should define data source in your weblogic with JNDI name hrDS.
      If you run your application in jdeveloper so you should define data source in integrated weblogic. you can connect to the weblogic console like(http://localhost:7101/console) and enter weblogic username and password like(weblogic/weblogic1) and from services menu define generic data sourse with name hrDS.

      Regards

      Delete
  6. Wao great link and perfect guidelines :) @Samah Nassar sir, I have done it completely it works very well ... but I also tried to generate the jasper report by a view which is based of the Parametrized view but it is not working there ....Any suggestion please ?

    ReplyDelete
    Replies
    1. Hi,
      I do understanding what is the meaning of generate the jasper report by a view??

      Jasper report should hold the query internally this view may has a parameter and you can pass this parameter as I explain in this example.
      Regards

      Delete
  7. Hi,
    Can you help me?
    I've trying to generate reports with jasper report but i have this error:
    Caused by: java.lang.NoClassDefFoundError: net/sf/jasperreports/engine/util/JRLoader
    at beans.JasperBean.runReport(JasperBean.java:88)

    The code line is:
    JasperReport template = (JasperReport) JRLoader.loadObject(fs);

    In the runReport method

    Any help?
    Thanks.

    ReplyDelete
    Replies
    1. Hi
      Check the version of ireport which you are use and the libraries you use in your application. Try to use the same version of ireport and the libraries in my example.
      Regards

      Delete
  8. Hi Samesh Sir,

    Please help me with this step.

    2- You should define datasource in your weblogic "as we write in the code datasource is hrDS"

    Can you upload a step-by-step tutorial for this step?

    Thank you in advance,

    Rahul

    ReplyDelete
    Replies
    1. Hi Rahul,

      I make small documentation for how you can define data source in weblogic you can download it from http://www.mediafire.com/view/?g7odbc06rpad1aa

      Regards,

      Delete
  9. Hi Sameh,
    Is it possible to download the pdf to the users OS (maybe using fileDownloadActionListener) as a file or open the pdf in a new browser tab or window and keep the current view of the jspx page?

    Thank you for this useful tutorial.

    ReplyDelete
    Replies




    1. Hi Ali ,
      You don't need to use fileDownloadActionListener you can insert inside button which will run the report af:clientListener which call javascript method to open the report in new window like:

      af:commandButton text="Run Report" id="cb1" action="#{jasper.runReportAction}">
      af:clientListener type="action" method="newWindow"/>
      /af:commandButton>


      and in your jsp page and this javascript method:
      function newWindow()
      {
      document.getElementById("f1").target = "_blank;targetfeatures=toolbar=no location=no directories=no menubar=no";
      }

      Delete
  10. HiSameh,
    Thank you so much for your clear explanation:)

    Ellerine sağlık ;)
    Betül

    ReplyDelete
  11. Thank you so much...Nicely explained.
    one question. I implemented the open in new window functionality and it is working. but one problem is if one report is opened in a window and without closing it, if I select another employee and generate report, then it gives error. the error is shown in the same window where the first report was shown. Error is "Error 403--Forbidden
    From RFC 2068 Hypertext Transfer Protocol -- HTTP/1.1:
    10.4.4 403 Forbidden
    The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable."

    ReplyDelete
    Replies
    1. Hi,
      I try your scenario put it work without error. You can send your code in my email to check it.

      Regards,

      Delete
  12. Hi,
    I tried it. But the program is not running as I am clicking on the print button I haven't got any response fro it. I follow all the steps and i am not getting any error also. Can you help me for it.

    Regards
    Saurabh

    ReplyDelete
    Replies
    1. Hi,

      Are you download my application and it is not running? are you sure that you make data source in weblogic?

      Delete