DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
The Latest "Software Integration: The Intersection of APIs, Microservices, and Cloud-Based Systems" Trend Report
Get the report
  1. DZone
  2. Data Engineering
  3. Databases
  4. Integrating BIRT With Wicket

Integrating BIRT With Wicket

Mark Clarke user avatar by
Mark Clarke
·
Sep. 07, 09 · Interview
Like (0)
Save
Tweet
Share
13.41K Views

Join the DZone community and get the full member experience.

Join For Free

In my previous article I setout a way we used to, at least partially, for a recent project. My next challenge on the project was how to integrate Birt into the Wicket framework? We have used Wicket in some of our previous projects, but in the past we have not had the need to delve beneath the Wicket API to understand its life cycle process, for the creation of a user sessions, population of wicket components from raw HTML request parameters and the handling of the request. This is a testament to Wicket's  wonderful architecture since we have been able to write non-trivial applications without having the go beneath the component abstraction provided by the framework;  however this was to change with BIRT.

How to Integrate BIRT into Your Application

There are essentially two ways to integrate BIRT (Business Intelligence and Reporting Tools) into your application:

  • Using the Birt Viewer application,
  • Using the Report Engine API

From the eclipse BIRT documentation the easiest way to integrate BIRT into your web app is to make use of the BIRT Viewer application.  Once I read the documentation it was clear to me that this method would be extremely bothersome for use with Wicket. For integration with the viewer one needs either to use JSP tags, which is not an option in Wicket, or to provide URL links that pass through the relevant report parameters in the query string, which is possible in Wicket.

Both these methods require one to install separate war file, or web app, for the BIRT Viewer. Although the BIRT Viewer does provide some great functionality, like ability to export to different formats, automatic creation of parameter dialog boxes and more, I was not keen on this deployment model. It  meant that each time I deployed our web app I would need to deploy a BIRT Viewer app as well. I decided to rather use the lower level API's to integrate BIRT. More information on how to integrate BIRT Viewer can be found at the Eclipse site.

BIRT Integration using the Report Engine API with Wicket

I decided the best approach was to use the Report engine API. Ths report engine api allows one to have   the report generated via API calls to the BIRT Runtime, and then one would have to handle the streaming of the report output to the client browser oneself. If I was using the servlet API directly it would be a simple matter of writing the output stream to the response object in the servlet's get or post method, but in Wicket the servlet API is hidden from direct access under the layers of the framework.

I do not cover the BIRT Reporting API in any detail as it is fairly straight forward to use. The code snippet at the end of the article shows how I used the API to generate the report but good information on how to use the BIRT API can be found at the  Eclipse BIRT site

Wicket's Request Life Cycle

To understand how one can get access to the response outputstream in Wicket, requires an understanding of the Wicket request life cycle flow. Sadly there is scant documentation on the Internet about the way the Wicket framework goes, from raw html request, to the framework calling your Wicket code. Some information can be found here but it glosses over the details of the RequestCycle object itself leaving one scratching your head as to where you can get hold of the outputstream.

After some investigation, the diagramme below captures my current understanding of the Wicket Request Life Cycle Proces.

The life cycle starts when the WicketFilter, as in the diagramme, or WicketServlet, depending on your web.xml setup, gets the raw HTML request. The Filter then wraps the HTMLServlerRequest and HTMLServletResponse object in Wicket's WebRequest and WebResponse objects and creates, or retrieves, a RequestCycle object. The RequestCycle class is abstract so the object returned is actually a WebRequestCycle object but most of the interesting work in done in the abstract RequestCycle object.

The RequestCycle object's "request" methond  is then called, to handle the remainder of the processing. The RequestCycle object requires a IRequestCycleProcessor object that actually does all of the work.  Our actual object is an instance of the WebRequestCycleProcessor class which extends the AbstractRequestCycleProcessor class, where, once again, most of the interesitng work is done. The WebRequestCycle object calls the methods on the WebRequestCycleProcessor in a inversion of control pattern during the processing of the "request" method.

Programme Flow of the WebRequest

The WebRequestCycleProcessor object calls the methods on the WebRequest object in a three step process in the following order:

  • Resolve - this method resolves the URL to the target component, IRequestTarget, that was called. It will invlolve creating the component from scratch, or retrieving it from the user session,
  • ProcessEvents - this calls any events that are applicable for the comoponent. In the diagramme above the "onSubmit()" event of a form button is being called. During this processing the RequestTarget can changed, with a call the the RequestCycle's "setRequesTarget" method. This will reset the three step process to start at "ProcessEvents" for the new requestTarget. (The RequestCycle object keeps a stack of RequestTargets to ensure all events are fired and cleaned up properly). In the case of BIRT we use the "onSubmit" method to change the IRequestTarget (See below) to the PDF output of the report engine. Thus when the "respond" method is called in the next step in the processes, it is called on our custom object rather than on the original  target object. 
  • Respond - this is where the "render" method from the target component is called. 

So we need to set our PDF report, generated by BIRT and the Report Engine APIs, as the RequestTarget once a button or link is clicked. Wicket uses the IResourceStream interface to link to resource streams. Most of the classes implementing this interface expect to get an input stream object from which to read the stream for final output to the response. In cases where you need to write directly to the output stream for dynamically created content, such as PDF reports, you need to create an object that implements the IResourceStreamWriter interface. The convenience class AbstractResourceStreamWriter is provided for easy extension and overriding of the "write" method.


So after this rather involved explanation, the code to actual get your BIRT pdf to display is quiet simple.

           public void onSubmit() {
               HashMap map = new HashMap();
              ....(process parameters from Wicket for the report and place in the map object)
         ReportParameterPage.this.generateReport(map,((WebApplication)ReportParameterPage.this.getApplication()).getServletContext().getRealPath(reportName.toString()));
}

    protected void  generateReport(final Map map,final String strReport){
               AbstractResourceStreamWriter writer = new AbstractResourceStreamWriter (){
                    public void write(OutputStream os) {
                        EngineConfig config = new EngineConfig();
                        String path = ((WebApplication)ReportParameterPage.this.getApplication()).getServletContext().getRealPath("WEB-INF/birt");
                        config.setEngineHome(path);
                        path = ((WebApplication)ReportParameterPage.this.getApplication()).getServletContext().getRealPath("WEB-INF/log");
                        config.setLogConfig(path,Level.FINE);
                        try {

                                Platform.startup(config);
                                IReportEngineFactory factory =(IReportEngineFactory) Platform.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
                                IReportEngine engine = factory.createReportEngine(config);
                                IReportRunnable report = engine.openReportDesign(strReport);

                                IRunAndRenderTask task = engine.createRunAndRenderTask(report);
                                task.setParameterValues(map);
                                PDFRenderOption options = new PDFRenderOption();
                                options.setOutputFormat("pdf");
                                options.setOutputStream(os);
                                task.setRenderOption(options);
                                task.run();
                                task.close();
                        } catch (BirtException e) {
                            logger.error(e.getLocalizedMessage());
                        }
                }

            public String getContentType() {
                return "application/pdf";
            }
         };
         this.getRequestCycle().setRequestTarget(new ResourceStreamRequestTarget(writer));
     }

Conclusion

Wicket is a great framework and BIRT is a great reporting tool, I hope that this article helps others in using the two technologies together. I also hope that we seee more articles explaining the inner workings of wicket, as I am sure this will help with the development of new 3rd party components.

Object (computer science) API Integration application Database Requests app Engine Framework Stream (computing)

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Spring Boot, Quarkus, or Micronaut?
  • Steel Threads Are a Technique That Will Make You a Better Engineer
  • Tracking Software Architecture Decisions
  • How To Choose the Right Streaming Database

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: