Jump to content
We've recently updated our Privacy Statement, available here ×

Generic Jasper Framework for web


Recommended Posts

By: Srinivas Nelakuditi - vasutech

Generic Jasper Framework for web

2005-04-15 13:23

Hi everyone,

 

My requirement was to integrate jasper reports into a web application and allow the developers to develop reports based on my work.

 

My flow works like this.

 

I have a controller servlet which forwards to a Request Handler based on the request id from the jsp.

 

I have designed a generic jsp page which has

parameters like

report name *.jrxml,

report data source *.java,

format

and any other input parameters required to

generate the report.

 

This jsp will be submitted to my controller with

action id as generateReport

 

The controller will forward the request to the request handler.

My request handler will accept the request

and will get this information from the request.

Jasper Name

DataSource Name

format

 

Then in the request handler I will load the jasper and get an instance of the datasource using

class.forName(dataSource)

Depending on the format paramter then

I will call specific handlers like html_handler, pdf_handler,xml_handler,xls_handler and csv_handler.

These handlers will then generate the content and set the content type and content dispostion for the browser the accept the content.

 

I have also designed a generic error.jsp to display errors during the entire process.

 

I am now in the process of integrating page by page viewer into this framework. Also I will be integrating JfreeChart for generating charts

and Quatz into the framework to make the reports to be schedulable.

 

This is just for your information.

mail me at suvatek@yahoo.com if you need any help.

 

 

 

By: Manfred Moser - mosabua

RE: Generic Jasper Framework for web

2005-04-18 13:23

So .. is it open source? where can we get it?

 

manfred

 

 

By: Srinivas Nelakuditi - vasutech

RE: Generic Jasper Framework for web

2005-04-20 22:29

Hi All,

 

To give you a better understanding , I am giving you complete walk through of my architecture and source code.

 

My architecture is like this

 

I have a

 

Controller ( servlet , All the requests and responses are handled by this CONTROLLER)

 

Request_Handler_Factory (java class)

 

Request_Handler (java class, for each request I will have one request handler,but for jasper reports I created a generic request handler to hanle any report )

 

and a lot of JSP's to handle the user interaction.

 

The Controller (servlet) will call the Request_Handler_Factory on every request as shown below:

 

// reqid is the request id coming as parameter from the html or jsp page

 

rh = Request_Handler_Factory.getRequestHandler(reqId);

 

// reqData can some times be formatted html generated by the request handler

 

// this formatted html will be flushed to the browser by the Controller

 

// but in most of the cases the the control passes to a jsp using request dispatcher

 

// from the request handler

reqData = rh.handleRequest(request, response, userSession,

servletcontext);

 

 

 

Now let us take a look at what Request_Handle_Factory is doing when the getRequestHandler method is called:

 

 

 

public static final String GENERATE_INTERAKTIV_REPORT = "generateInteraktivReport";

 

if (requestId.equals(GENERATE_INTERAKTIV_REPORT)) {

rh = new InteraktivReportingEngineRH();

 

}

 

return rh;

 

 

 

so as shown above the Request_Handle_Factory will return the object of request handler for the request id obtained from the request

 

 

 

Now let us get to the most important part of the story: now we are going to look at

 

what happens when the Controler exectues the below code after obtaining handle

 

to the request handler object.

 

 

 

reqData = rh.handleRequest(request, response, userSession,

servletcontext);

 

 

 

 

 

So now our rh is an object of InteraktivReportingEngineRH

 

So take a look at InteraktivReportingEngineRH source code

 

 

 

--------------------------------Source Code Self Explanatory -------------------------------

 

import javax.servlet.ServletContext;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.bos.UserSession;

import com.interaktiv.datasource.*;

import net.sf.jasperreports.engine.*;

import net.sf.jasperreports.engine.*;

import net.sf.jasperreports.engine.util.*;

import net.sf.jasperreports.engine.export.*;

import java.io.*;

import java.util.*;

import javax.servlet.*;

import javax.servlet.http.*;

 

/*******************************************************************************

* @author vasutech

 

* Nothing Is Impossible

 

* CODE LOCKED NO CHANGES ALLOWED

******************************************************************************/

public class InteraktivReportingEngineRH implements RequestHandler {

 

static Logger logger = Logger.getLogger(InteraktivReportingEngineRH.class

.getName());

 

/***************************************************************************

* These are all the tasks that Interaktiv will do by version 1.0

* pdf,html,xls,csv and xml tasks are working. print task(silent print) will

* be looked at according to the requirement

**************************************************************************/

private static final String TASK_PRINT = "print";

 

private static final String TASK_PDF = "pdf";

 

private static final String TASK_XML = "xml";

 

private static final String TASK_HTML = "html";

 

private static final String TASK_XLS = "xls";

 

private static final String TASK_CSV = "csv";

 

String format = TASK_PDF;

 

public String handleRequest(HttpServletRequest request,

HttpServletResponse response, UserSession us, ServletContext sc) {

 

logger

.info("Entered handleRequest() method in InteraktivReportingEngineRH ");

 

String jasperName = "";

String dataSourceName = "";

byte[] output = null;

/***********************************************************************

* Here we are getting the input parameters from the request object

* Paramters parsed are as follows: jasperName: Name of the Compiled

* jasper name dataSourceName: Name of the dataSource class name format:

* the format in which the report must be written All the above 3

* paramters must be available in the request object for this class to

* function properly

**********************************************************************/

try {

jasperName = (String) request.getParameter("REPORT_JASPER_NAME");

logger.info("jasper name is " + jasperName);

dataSourceName = (String) request

.getParameter("REPORT_DATASOURCE_NAME");

logger.info("data Source name is " + dataSourceName);

format = request.getParameter("format");

logger.info("format requested is " + format);

} catch (Exception e) {

logger.error("Error in getting the input parameters", e);

forwardToErrorJSP(request,response,e);

}

try {

// Getting a handle to the compiled report

File reportFile = new File(sc.getRealPath("/reports/" + jasperName));

/***********************************************************************

* This HashMap is available for every report This has useful

* information like company name and employee name Add more information

* as you deem important to the hash map But the information must not be

* specific for one report, it must be generic information

**********************************************************************/

Map parameters = new HashMap();

parameters.put("CompanyName", ""

+ us.getCompanyInfoObj().getCompanyName());

parameters.put("UserName", us.getEmployeeObj().getEmployeeName());

 

/***********************************************************************

* This is the best part of this program, Here dynamically we are

* loading the datasource class, then we are looking up for the

* constructors and we are instantiating an object of the datasource

* with HttpServletRequest object as parameter. We are dynamically

* loading and using reflection to make this class generic to work for

* any report with any datasource. If you compare with RHFactory this is

* a great improvement.

**********************************************************************/

 

logger.info("about to use class.forname to load the datasource");

Class DataSourceClass = Class

.forName("com.sceptreinc.easybiz.interaktiv.datasource."

+ dataSourceName);

for (int i = 0; i < DataSourceClass.getConstructors().length; i++) {

java.lang.reflect.Constructor[] dataSourceConstructor = DataSourceClass

.getConstructors();

logger.info(DataSourceClass.getConstructors());

}

 

logger.info("created new instance of datasource");

 

java.lang.reflect.Constructor constr = DataSourceClass

.getConstructors()[0];

Object ob[] = { (Object) request };

/*******************************************************************

* Here we are Loading the *.jasper(compiled report) Using

* JasperFillManager.fillReport method we are filling the compiled

* report with data from our data source. we get the JasperPrint

* object which is the filled report. This JasperPrint object can

* then be exported to any format

******************************************************************/

 

JasperReport jasperReport = (JasperReport) JRLoader

.loadObject(reportFile.getPath());

 

JasperPrint jasperPrint = JasperFillManager.fillReport(

jasperReport, parameters, (JRDataSource) constr

.newInstance(ob));

 

/*******************************************************************

* From here we are processing according to the format requested by

* the user. Depending on the format requested we are exporting the

* JasperPrint object to various formats like html,csv,xls,pdf,xml.

* Before sending the output stream to the browser, we are setting

* the content type and content-dispostion. Content-disposition

* seems to be nice way of informing the browser about the

* application to be used to accept the stream being sent from

* server

******************************************************************/

/*******************************************************************

* Processing to generate the pdf format, content type is

* application/pdf, content-disposition is report.pdf

******************************************************************/

 

if (format.equals(TASK_PDF)) {

output = JasperExportManager.exportReportToPdf(jasperPrint);

response.setContentType("application/pdf");

response.setHeader("Content-Disposition",

"inline; filename=report.pdf");

ServletOutputStream outputStream = response.getOutputStream();

response.setContentLength(output.length);

outputStream = response.getOutputStream();

outputStream.write(output, 0, output.length);

outputStream.flush();

outputStream.close();

} else {

JRExporter exporter = null;

/***************************************************************

* Processing to generate the html format content type is

* text/html content-disposition is report.html

**************************************************************/

if (format.equals(TASK_HTML)) {

response.setContentType("text/html");

exporter = new JRHtmlExporter();

response.setHeader("Content-Disposition",

"inline; filename=report.html");

Map imagesMap = new HashMap();

request.getSession().setAttribute("IMAGES_MAP", imagesMap);

exporter.setParameter(JRExporterParameter.JASPER_PRINT,

jasperPrint);

exporter.setParameter(JRHtmlExporterParameter.IMAGES_MAP,

imagesMap);

exporter.setParameter(JRHtmlExporterParameter.IMAGES_URI,

"image?image=");

/***********************************************************

* Processing to generate the xls or MS-EXCEL format content

* type is application/vnd.ms-excel content-disposition is

* report.xls

**********************************************************/

} else if (format.equals(TASK_XLS)) {

response.setContentType("application/vnd.ms-excel");

response.setHeader("Content-Disposition",

"inline; filename=report.xls");

exporter = new JRXlsExporter();

/***********************************************************

* Processing to generate the csv or MS format content type

* is text/plain content-disposition is report.csv

**********************************************************/

} else if (format.equals(TASK_CSV)) {

response.setContentType("text/plain");

response.setHeader("Content-Disposition",

"inline; filename=report.csv");

exporter = new JRCsvExporter();

/***********************************************************

* Processing to generate the XML format content type is

* text/xml content-disposition is report.xml

**********************************************************/

} else if (format.equals(TASK_XML)) {

response.setContentType("text/xml");

response.setHeader("Content-Disposition",

"inline; filename=report.xml");

exporter = new JRXmlExporter();

}

output = exportReportToBytes(jasperPrint, exporter);

response.setContentLength(output.length);

ServletOutputStream outputStream;

outputStream = response.getOutputStream();

outputStream.write(output);

outputStream.flush();

outputStream.close();

}

} catch (JRException e) {

logger.error("error in InteraktivReportingEngineRH", e);

forwardToErrorJSP(request,response,e);

} catch (Exception e) {

logger.error("error in InteraktivReportingEngineRH", e);

forwardToErrorJSP(request,response,e);

}

// I hope the control will never reach here to return this statement

forwardToErrorJSP(request,response,new Exception());

response.setContentType("text/html");

return "<html><body>error in interaktiv report</body></html>";

}

 

public String getContentType() {

String returnString = "";

if (format.equals("pdf"))

returnString = "application/pdf";

if (format.equals("html"))

returnString = "text/html";

if (format.equals("xsl"))

returnString = "application/vnd.ms-excel";

if (format.equals("csv"))

returnString = "text/plain";

if (format.equals("xml"))

returnString = "text/xml";

return returnString;

}

 

private byte[] exportReportToBytes(JasperPrint jasperPrint,

JRExporter exporter) throws JRException {

byte[] output;

ByteArrayOutputStream baos = new ByteArrayOutputStream();

exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);

exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);

exporter.exportReport();

output = baos.toByteArray();

return output;

}

/*****************************************************************

* This method will forward the control to interaktiv_error.jsp

* The jsp will then display the reason for error and all

* the input parameters.

* This is a faster way of showing the user and developer what

* happenned to thier request if an error occurs.

* This will make the development easy as they need not go through

* the process of going through the logs.

*****************************************************************/

private void forwardToErrorJSP(HttpServletRequest req,

HttpServletResponse res,Exception e) {

try {

System.out.println("reached the forwardToErrorJsp in interaktivReportingEngineRH");

HttpSession session = req.getSession();

if(session!=null)

{

session.setAttribute("Interaktiv_error",(Exception)e);

}

System.out.println("reached here");

RequestDispatcher rd = req

.getRequestDispatcher("/jsp/interaktiv_error.jsp");

System.out.println("reached here too");

rd.forward(req, res);

System.out.println("should not have reached here");

} catch (Exception ex) {

 

}

}

}

--------------------------------------------end of source code ---------------------------------------------------

 

 

 

So after looking at the above code, every thing might have been clear to you ( If not, send me your corporate jet.)

 

 

 

So let me give a simple walk through here:

 

 

 

Every Report might require some input parameters like start data , end date, company name,

 

client name , invoice number etcetra.

 

so my jsp will be passing all the above parameters along with these parameters

 

 

 

--------------Source code from jsp ---------------------------------------

 

<input type="HIDDEN" name="REQ_ID" value="generateInteraktivReport">

 

<input type="HIDDEN" name="REPORT_JASPER_NAME" value="SalesTransactionReport.jasper">

 

<input type="HIDDEN" name="REPORT_DATASOURCE_NAME" value="SalesTransactionDataSource">

 

------------------End of source code from jsp --------------------------------------------

 

So here I am passing the request id, the compiled report name and the data source to be used

to fill the report. The above parameters are mandatory if my frame work has to run.

 

After this as you know , when the user fills the report and hits the submit button, It will get submitted to my Controller (servlet), which again will call the RequestHandlerFactory and will get handle to the request handler.

 

After getting the hanle to the request handler the Controller will call the handleRequest method on the request hanlder object.

 

In our case the request handler is the InteraktivReportingEngineRH, for which I have provided the complete source code above.

 

As you can see the InteraktivReportingEngineRH will do the following things

 

1) load the jasper file ( compiled jasper report )

2) Depending on the format required the report is generated in the format and the response is flushed back to the browser.

 

now let me also give the code for data source, which will fill the report

 

( you need to write your own data source to fill the report, I am giving this just for your

 

reference and you can use this as a template )

 

----------------Source code for data source class -----------------------------

 

import net.sf.jasperreports.engine.JRDataSource;

import net.sf.jasperreports.engine.JRException;

import net.sf.jasperreports.engine.JRField;

import javax.servlet.http.HttpServletRequest;

import java.util.Calendar;

import java.util.Vector;

import com.interaktiv.datasource.*;

import com.rh.InteraktivReportingEngineRH;

 

import org.apache.log4j.Logger;

 

public class SalesTransactionDataSource implements JRDataSource

{

static Logger logger = Logger.getLogger(SalesTransactionDataSource.class.getName());

public SalesTransactionDataSource()

{

}

public SalesTransactionDataSource(HttpServletRequest request)

{

generateData(request);

}

 

private int index = -1;

private Vector _returnVec = new Vector();

 

private static Statement _stmtOid;

 

private static String _startDate;

 

private static String _endDate;

 

private static ResultSet _rs;

 

private Vector invoiceVec = new Vector();

private Vector customerVec = new Vector();

private Vector itemVec = new Vector();

private Vector shippedQtyVec = new Vector();

private Vector sellingpriceVec = new Vector();

private Vector itemCategoryVec = new Vector();

private Vector customerNameVec = new Vector();

private Vector itemNameVec = new Vector();

private Vector invoiceDateVector = new Vector();

private Vector itemCategoryNameVector = new Vector();

 

public void generateData(HttpServletRequest request)

{

/* The code in this is hardcoded with jdbc

* Feel free to implement using easybiz classes

* This was done for testing the functionality

*

*/

long start = System.currentTimeMillis();

String startTime = ""+Calendar.getInstance().getTime();

//System.out.println("fdsgfdsg");

String st_date = (String)request.getParameter("start_date");

String en_date = (String)request.getParameter("end_date");

 

//_startDate = "2004-11-15 01:10:20"; //hardcoded start date

//_endDate = "2005-02-15 01:10:20"; //hardcoded end date

_startDate = st_date;

_endDate = en_date;

 

try {

// I had to remove the business logic code here as I dont want to

// get into trouble later

 

}

} catch (Exception exc) {

System.err.println("ERROR "+exc);

}

System.out.println("StartTIme is "+startTime);

String endTime = ""+Calendar.getInstance().getTime();

System.out.println("endTIme is "+endTime);

System.out.println("Compile time : " + (System.currentTimeMillis() - start));

System.out.println("start date from jsp is "+st_date);

System.out.println("end date from jsp is"+en_date);

 

}

 

 

// this method is a must if we implement JRDataSource

public boolean next() throws JRException

{

//logger.info("called this next()");

index++;

 

return (index < customerNameVec.size());

}

 

 

// This method will return values according to the field

// names in report

public Object getFieldValue(JRField field) throws JRException

{

//logger.info("called this getFieldValue");

Object value = null;

String fieldName = field.getName();

 

if ("Customer_Name".equals(fieldName))

{

value = customerNameVec.get(index);

}

else if ("Item_Name".equals(fieldName))

{

value = itemNameVec.get(index);

}

else if ("Invoice".equals(fieldName))

{

value = invoiceVec.get(index);

}

else if ("Selling_Price".equals(fieldName))

{

value = sellingpriceVec.get(index);

}

else if ("Date".equals(fieldName))

{

value = invoiceDateVector.get(index);

}

else if ("Shipped_Qty".equals(fieldName))

{

value = shippedQtyVec.get(index);

}

 

return value;

}

 

 

}

 

----------------------- source code over for data source ------------------------------------

 

The above code is working and has been tested.

I am still working on some parts to add more functionality and make it easy to work with, I will post the entire source code in early July.

Link to comment
Share on other sites

  • Replies 0
  • Created
  • Last Reply

Top Posters In This Topic

Popular Days

Top Posters In This Topic

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...