We will now create and configure a Listener and a Servlet respectively inside our project. Finally, we will initiate our server and test the service by executing our report inside a web browser.
Listeners are used to process events that are divided into categories and are generated by the server at various levels. In our case, we are interested in listening to events at a container level, particularly at the time at which the container is initiated. This is done so that the users do not have to pay the price of initializing components, thus improving the users' experience in a noticeable way.
We will head to the Project Explorer panel, select the node named prd5Ch14, right-click on it, and then go to New | Other.... In the following window, inside the Web category we will select the Listener item and then click on Next > so that we are presented with the corresponding wizard.
com.prd.web.listeners
InitListener
InitListener.java
and replace it with the following code:package com.prd.web.listeners; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot; @WebListener public class InitListener implements ServletContextListener { public void contextInitialized(ServletContextEvent event) { ClassicEngineBoot.getInstance().start(); } public void contextDestroyed(ServletContextEvent event) { } }
To indicate that this is a Listener, we are making use of the @WebListener
annotation, which is found right before the definition of the class. The interfaces implemented by ServletContextListener
define what types of events are being listened to. In our case, we are interested in executing the PRD engine initialization code every time the container is started; that is why we included the line ClassicEngineBoot.getInstance().start();
within the contextInitialized()
method. We should now save the changes made to this file.
com.prd.web.actions
RunReport
We will click on the Next > button to continue.
In the URL Mapping section, we will select the /RunReport item, click on the Edit... button, place the name /runReport
, and then click on OK.
We will now click on the Finish button to continue.
RunReport.java
and copy the following code. We should pay special attention to the comments (pieces of text within /*
and */
) placed throughout the code since they will help us understand it:/* Header: contains the package and necessary imports. */ package com.prd.web.actions; import java.io.File; import java.io.IOException; import java.net.URL; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.pentaho.reporting.engine.classic.core.MasterReport; import org.pentaho.reporting.engine.classic.core.ReportProcessingException; import org.pentaho.reporting.engine.classic.core.modules.output.pageable.pdf.PdfReportUtil; import org.pentaho.reporting.engine.classic.core.modules.output.table.base.StreamReportProcessor; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.AllItemsHtmlPrinter; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.FileSystemURLRewriter; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.HtmlPrinter; import org.pentaho.reporting.engine.classic.core.modules.output.table.html.StreamHtmlOutputProcessor; import org.pentaho.reporting.libraries.repository.ContentIOException; import org.pentaho.reporting.libraries.repository.ContentLocation; import org.pentaho.reporting.libraries.repository.DefaultNameGenerator; import org.pentaho.reporting.libraries.repository.file.FileRepository; import org.pentaho.reporting.libraries.resourceloader.Resource; import org.pentaho.reporting.libraries.resourceloader.ResourceException; import org.pentaho.reporting.libraries.resourceloader.ResourceManager; /* The next line defines that this class is a Servlet, as well as the URL Mapping. */ @WebServlet("/runReport") public class RunReport extends HttpServlet { private static final long serialVersionUID = 1L; /* Method doGet(): this determines that this class will only respond to requests of the type HTTP GET. */ protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { /* The following three lines take the parameters sent by the client and assign them to variables. In our case, we need "year" and "month" so that we can pass them to the PRD engine, since in our report we have defined the parameters "SelectYear"and "SelectMonth" respectively. The parameter "outputType" will help us to determine which type of output was required by the user.*/ Integer year = Integer.parseInt(request.getParameter("year")); Integer month = Integer.parseInt(request.getParameter("month")); String outputType = request.getParameter("outputType"); String errorMsg = ""; try { /* The call to doReport() is the one that will finally process the report.*/ doReport(year, month, outputType, response); } catch (Exception e) { e.printStackTrace(); errorMsg = "ERROR: " + e.getMessage(); } /* The following if checks if an error has occurred, in which case creates a string with the error message and stores it in an attribute of the "request" object, and then performs a redirect to the index. */ if (errorMsg.length() > 0) { request.setAttribute("errorMsg", errorMsg); RequestDispatcher dispatcher = getServletContext() .getRequestDispatcher("/index.jsp"); dispatcher.forward(request, response); } } /* Method doReport(): */ private void doReport(Integer year, Integer month, String type, HttpServletResponse response) throws ReportProcessingException, IOException, ResourceException, ContentIOException { /* -> Global Setup */ ResourceManager manager = new ResourceManager(); manager.registerDefaults(); URL urlToReport = new URL("file:" + getServletContext().getRealPath( "WEB-INF/report/11_Adding_Charts.prpt")); Resource res = manager.createDirectly(urlToReport, MasterReport.class); MasterReport report = (MasterReport) res.getResource(); report.getParameterValues().put("SelectYear", year); report.getParameterValues().put("SelectMonth", month); response.setHeader("Content-disposition", "filename=out." + type); /* -> Output Type: pdf & html */ if (type.equalsIgnoreCase("pdf")) { response.setContentType("application/pdf"); PdfReportUtil.createPDF(report, response.getOutputStream()); } if (type.equalsIgnoreCase("html")) { response.setContentType("text/html"); String fileName = "_out" + System.currentTimeMillis() + "." + type; File folderOut = new File(getServletContext().getRealPath( "/out/" + System.currentTimeMillis())); if (!folderOut.exists()) { folderOut.mkdirs(); final FileRepository targetRepository = new FileRepository( folderOut); final ContentLocation targetRoot = targetRepository.getRoot(); final HtmlPrinter printer = new AllItemsHtmlPrinter( report.getResourceManager()); printer.setContentWriter(targetRoot, new DefaultNameGenerator( targetRoot, fileName)); printer.setDataWriter(targetRoot, new DefaultNameGenerator( targetRoot, "content")); printer.setUrlRewriter(new FileSystemURLRewriter()); final StreamHtmlOutputProcessor outputProcessor = new StreamHtmlOutputProcessor( report.getConfiguration()); outputProcessor.setPrinter(printer); final StreamReportProcessor reportProcessor = new StreamReportProcessor( report, outputProcessor); reportProcessor.processReport(); reportProcessor.close(); String route = "out/" + folderOut.getName() + "/" + fileName; response.sendRedirect(route); } } } }
We will now save the changes to this file.
http://localhost:8080/prdweb/runReport?year=2005&month=6&outputType=html
The parameters we have sent are as follows:
year=2005
month=6
outputType=
html
We can keep testing by changing the values of the Parameters in the URL; for example, it would be interesting to see what the output of the report is if we placed outputType=pdf
in the URL.
We created a Listener inside our project so that it performs the PRD's API initialization; we configured it and modified the code within the file named InitListener.java
. We also created a Servlet inside our project so that it manages requests, processing, and routings; we configured it and modified the code within the file named RunReport.java
. Finally, we started our server (Apache v7.0 Server at localhost) and tested the service by opening the following URL inside a web browser: http://localhost:8080/prdweb/runReport?year=2005&month=6&outputType=html
.