Вы находитесь на странице: 1из 23


Crystal Reports XI for J2EE Startup Guide

July 2005

Version 2.0

2005 Business Objects Corp. All rights reserved.

Business Objects Starter Kit: Crystal Reports

Crystal Reports XI for J2EE Startup Guide

Citigate Hudson January 2005 Summary: This whitepaper provides step-by-step instructions on the details of generating and displaying reports in various deployment scenarios and application environments using Crystal Reports XI for Java2, Enterprise Edition.

What is the Crystal Reports XI for J2EE Startup Guide?
The Crystal Reports for J2EE Startup Guide (hereafter known as the guide) is intended to get competent J2EE developers, who are new to Crystal Reports or familiar with older versions, up to speed quickly, using the product in a variety of reporting scenarios. The guide presents several scenario-driven approaches to designing and building reports with Crystal Reports XI. The guide walks through three different reporting scenarios. The scenarios increase in difficulty, and are described below:

Scenario Basic Intermediate

Description A Tabular report, designed using the Expert, utilizing a standalone report file deployed as part of a JSP-based Web application. A Master-Detail report with drill-down capabilities, designed manually, utilizing a database view (instead of a straight table) as the data source and using the Crystal Reports Java Reporting Components tag library as the presentation layer code. We discuss how to pass database credentials in to a report (so that they need not be deployed with the report itself), how to pass parameters in to the report (to constrain the data displayed as part of the report), and how to export to PDF for display within the browser.


The guide provides the most benefit to developers who are familiar with servlets, JSP, and the general concepts of J2EE. No particular IDE is assumedall report development is presumed to be done using the Crystal Reports report development environment, rather than using any of the IDE integrations offered by Crystal Reports. In addition, the guide uses the Xtreme Database sample shipped with Crystal Reports, which installs itself as an ODBC data source. This means that the sample guides will be using the JDBC-ODBC driver to access and report off of this database, something that in general should be avoided for any production system, since the Sun JDBC-ODBC driver is fairly old and fragile. (We use this database so as to provide a baseline that will be familiar to Crystal developers and other documentation and guides.) Because of the fragility of the JDBC-ODBC driver, we will be designing the reports using the direct ODBC connection support in Crystal Reports, but at runtime the data will be coming through the JDBC-ODBC driver, just to prove that this is a 100% Pure Java (at least as much as it can be, using that driver) solution.

To report directly off JDBC, manually edit the CRConfig.xml file, which is located in the Program Files\Common Files\Business Objects\3.0\java directory and ensure that the <JavaDir> location is set to the location of the JRE. For example, <JavaDir>C:\j2sdk147\bin</JavaDir> Although the J2EE Specification is vendor-agnostic, and encourages developers to write code that can be deployed into any J2EE-compliant application server environment, unfortunately it is far more difficult to write about J2EE applications in a concrete fashion without mentioning any vendor-specific details. Rather than try and work around clumsy sentences such as deploy the web application using the vendors web application deployment tool to a servlet context name of Example, and ensure that the deployment descriptor contains references, we will assume the deployment environment is the

latest version of Tomcat (5.0.27, as of this writing), installed on a Windows box at C:\Tomcat5.01, and is running on port 8080.

Basic Reporting Scenario

The Basic Reporting Scenario illustrates the simplicity of adding reporting capabilities to a J2EE web-based application. This scenario creates a report using the Crystal Reports design-time wizards, a.k.a. Experts that come with the Crystal Reports Designer

Be careful, by the way; if the Tomcat installation path contains a space, you may get errors that complain that Report location must be set at runtime. This is because despite support within Java for file- or directory-names with embedded whitespace, its still awkward to work with names-with-spaces in them. The workaround, of course, is to install Tomcat to a directory without spaces in it.

environment. No code will be necessary to generate the report, and only a minimal amount of code will be necessary to wire up the report into the J2EE application.

To create the sample, start the Crystal Reports environment and begin the design of a new report using File | New | Standard Report, as per Figure 1 below:

Next you will need to specify the data source to generate the report from. Generally, when developing reports designed to be run from the J2EE environment, you will want to use JDBC/JNDI database connections, since thats how the report will be fetching data at runtime. Double-click ODBC (RDO) (under the Create New Connection folder in the Available Data Sources list), and the ODBC (RDO) dialog will appear, listing the available ODBC DSNs to use in order to connect to the database. In our case, were looking to connect against the Xtreme Sample Database 11 ODBC DSN that is installed as part of the Crystal Reports XI environment. Click Next, and the wizard will next present Connection Information for you to fill in User ID, password, and database values.

Once weve connected to the database, specify the tables to add to the report by opening up the Tables node underneath the data source, and either double-clicking or selecting and clicking the >> button to insert the table names into the right-hand column. Select the Customer table, and click Next. Select which columns should be displayed as part of this report by, again, doubleclicking the column names in the left-hand tree. Select the following columns:

Customer ID Customer Name Contact First Name, Contact Last Name, and Contact Position Address1 and Address2 City, Region, Country and Postal Code

When these have been selected, click Next:

We want to group the report by Country, so on this next page double click the Customer.Country item underneath Grouping Fields in the left-hand pane, and click Finish to generate the report.

What we end up with (after the Crystal Reports Designer churns for a while, depending on how much data is in the data source already) is something similar to the following:

At this point, the report is created and ready to be integrated into the J2EE application. The last few steps involve setting up the J2EE application server environment to host the report from the web application. For this, we will need to do a few installation/deployment tasks in order to enable Crystal Reports XI to execute successfully from the application server environment. Save the report as Report1.rpt to a location of your choice (well copy it from there into the web application directory in just a bit), and close down the Crystal Reports XI designer. Several steps need to be done in order to execute the report from the J2EE web application. In this example, well use Tomcat. Well assume the web application that will host the reporting application is running already in a web application called CRStartupGuide, and is already installed as per the Tomcat administrative interface): 1. Copy Java Reporting Component (JRC) and necessary support .jars from C:\Program Files\Common Files\Business Objects\3.0\java\lib and C:\Program Files\Common Files\Business Objects\3.0\java\lib\external into the WEB-INF\lib folder inside the web application or .war file. 2. As our report was created off ODBC, which is not a pure Java database connection type, we need to map the ODBC connection to JDBC using the JDBCODBC bridge in order for the JRC to connect and query the database for report data. To do this, include the following in the <env-entry> in the CRStartupGuides web.xml file: <env-entry> <env-entry-name>jdbc/Xtreme Sample Database 11</env-entryname>

<env-entryvalue>!sun.jdbc.odbc.JdbcOdbcDriver!jdbc:odbc:Xtreme Sample Database 11</env-entry-value> <env-entry-type>java.lang.String</env-entry-type> </env-entry> 3. Copy the crystalreportviewers11 directory (found in C:\Program Files\Common Files\Business Objects\3.0) to a subdirectory of the same name directly underneath the CRStartupGuide directory (as a peer to WEB-INF). Ensure that all contents, both files and subdirectories, are copiedthere should be about 150 files in all. This name of this subdirectory in the CRStartupGuide directory is not important, so long as it matches up when referenced in the web.xml file, which must have the following block added: <context-param> <param-name>crystal_image_uri</param-name> <param-value>crystalreportviewers11</param-value> </context-param> Generally, developers will leave the name as is (crystalreportviewers11). 4. Copy the CRconfig.xml file into the WEB-INF/classes subdirectory from C:\Program Files\Common Files\Business Objects\3.0\java directory. 5. Copy the report file itself into the root of the webapp. 6. Write the JSP page (call it basic.jsp, in the root of the web application subdirectory) that will ask the Crystal Reports rendering engine to take the passed report and generate HTML from it, echoing it back to the webapps current client. This takes two principal steps. First, we need to create a report source that the report viewer will use as the input for generating the report, then we need to create a report viewer to use to process the HTTP request. In Crystal Reports XI, the report source is obtained from the ReportClientDocument, which is used to open the RPT file, as shown here: <%@page contentType="text/html"%> <%@page pageEncoding="UTF-8"%>

<%@page import="com.crystaldecisions.reports.sdk.*" %> <%@page import="com.crystaldecisions.sdk.occa.report.reportsource.*" %> <%@page import="com.crystaldecisions.sdk.occa.report.lib.*" %>

<% String reportName = "report1.rpt";

try {

//check to see if the report source already exists Object reportSource = session.getAttribute("reportSource");

//if the report source has not been opened if (reportSource == null) { //---------- Create a ReportClientDocument -----------ReportClientDocument oReportClientDocument = new ReportClientDocument();

//---------- Set the path to the location of the report soruce -------------

//Open report. oReportClientDocument.open(reportName, 0);

//Get the report source reportSource = oReportClientDocument.getReportSource();

//Cache report source. //This will be used by the viewer to display the desired report. session.setAttribute("reportSource", reportSource); } //Redirect to the viewer page. response.sendRedirect("CrystalReportViewer.jsp");

} catch(ReportSDKException e) { out.print(e); }

7. Create a second page, called CrystalReportViewer.jsp, this will contain the calls to the Viewer SDK, as shown below: <%@page contentType="text/html"%>

<%@page pageEncoding="UTF-8"%>

<%@page import="com.crystaldecisions.report.web.viewer.*"%> <%@page import="com.crystaldecisions.reports.sdk.*" %> <%@page import="com.crystaldecisions.sdk.occa.report.reportsource.*" %>

<% //Get the IReportSource object from sesion and pass it to the viewer IReportSource reportSource = (IReportSource)session.getAttribute("reportSource");

//create the CrystalReportViewer object CrystalReportViewer oCrystalReportViewer = new CrystalReportViewer();

//set the reportsource property of the viewer oCrystalReportViewer.setReportSource(reportSource);

//set viewer attributes oCrystalReportViewer.setOwnPage(true); oCrystalReportViewer.setOwnForm(true);

//set the CrystalReportViewer print mode oCrystalReportViewer.setPrintMode(CrPrintMode.ACTIVEX); //refresh the CrystalReportViewer if necessary (only required once) if (session.getAttribute("refreshed") == null) { oCrystalReportViewer.refresh(); session.setAttribute("refreshed", "true"); }

oCrystalReportViewer.processHttpRequest(request, response, getServletConfig().getServletContext(), null); %> 8. Browse to http://localhost:8080/CRStartupGuide/basic.jsp to view the report:

Scenario Conclusion
The Basic scenario describes how easy it is to add reporting to a J2EE web-based application. However, most real-world reporting demands more sophisticated reports than just simple dumps of tables, even when grouped as above. The Intermediate scenario walks through the creation and design of a report more commonly seen in production, a master-detail report.

Intermediate Scenario
In this scenario, the application needs a master-detail report with drill-down capabilities; users wish to select an item from a high-level view (the master report), select it, and be greeted with a host of informational data about the item selected in another view (the detail report). The report for this scenario is created by creating a Blank Report in Crystal Reports. A blank report form will be generated in the designer (the Database Expert will open immediately after clicking OK; for now, just ignore it, but dont close it):

As you can see, its not unlike other IDEs youre probably familiar withthe panel on the right is the Explorer, where major elements of the report can be explored and referenced, and the center area is the design view of the report itself. (As we populate the report with fields from a table, a new view will open up, previewing the report in a more WYSIWYG fashion so you can ensure that the report will look the way it should.) If the Database Expert is closed (perhaps you clicked Cancel in the dialog that came up just after creating the new report), bring it up by selecting Database|Database Expert from the menu bar at the top. Navigate once again to the Xtreme Sample Database 11 ODBC DSN database in the Data connection tree on the left, and open it if it isnt already opened. (If you have a large number of ODBC data sources, scrolling through them all can become tediousfeel free to right-click on the Xtreme Sample Database 11 node and select Add to Favorites so it will be available under the Favorites node in the Data connection tree.) Select the Top Customers view from underneath the Views node in the Xtreme Sample Database 11 database, and click OK to close:

At this point, the Database Fields node in the Field Explorer to the right will become expandable, and when expanded will contain the fields that are available to be placed within this report: {{ FieldExplorer.PNG }} Building a report from scratch involves manually placing the report fields from the Field Explorer (at right) into the design view of the Crystal Reports designer. Simply drag the following fields from the Field Explorer to a position on the report itself: Add the following fields to the Report Header section: o Text Object whose text is Top Customers Drill Down Report. Text Objects can be added by selecting Insert|Text Object from the menubar at the top of the application. Place the Text Object to the left of the Header area, fill in the text, and stretch the size of the TextObject box so all the text can be seen. Insert a Print Date field object just to the right of the Text Object. The easiest way to insert a Print Date field object is to drag one from the Special Fields node (Print Date) in the Field Explorer to the Report Header section. Insert a Print Time field object in much the same manner, again just to the right of the date object just inserted.

Add the following fields to the Group Header section: o From the menubar, select Insert | Group and at the Grouping dialog that opens, select the Top_Customers Country field. This will be the master view, looking at all of the Top Customers by country first. (Well let people drill in on the details of each country first in a few minutes.)

o o o Next, right-click on the Running Total Fields node in the Field Explorer, and select New at the context menu that pops up. This will allow you to create a new Running total for the group. In this particular case, we want to see the total sales of the Top Customers by Country, so in the Running Totals dialog that follows, just select the Top_Customers Last Years Sales field and hit the > button to use it. The default operation, sum is sufficient. When you click OK, a new field will have been added to the Report Explorer, usually by the name of RTotal0. Simply drag this field to the Group Header section, right next to the Group #1 Name field introduced by the last step.

Add the following fields to the Details Section of the report: o Individually drag the Customer Name, Last Years Sales, Contact First Name and Contact Last Name fields into the Details Section of the report. Note that Crystal Reports will also add column headers right above the location of the fields in the Details Section. Lastly, right-click on the Details section in the left-hand panel (directly underneath the Group Header text), and select Hide (Drill Down OK) in the context menu. This is what will hide the details from the master report, allowing users to double-click on just the items of interest to them.

When finished, the Crystal Report designer should look something like the following: {{ MasterDetail.PNG }} Save this report as MasterDetail.rpt. Next, we need to deploy this report as part of a web application. As with the Basic Scenario, create a new web application in the Tomcat server (or reuse the existing one we created earliercreating a new one will reinforce the deployment steps necessary to get Crystal Reports XI Java Reporting Components to work in a J2EE environment, reusing the existing one will get you up and running more quickly), and again go through the steps listed above: 1. Copy the .jars to /WEB-INF/lib 2. Copy the crystalreportviewers11 subdirectory and mark up the deployment descriptor accordingly. Remember that this needs to be a <context-param>, not a servlet <init-param> value. 3. Copy the CRconfig.xml file to /WEB-INF/classes.


Copy the MasterDetail.rpt file into the root of the web application.

Now, however, when we create the intermediate.jsp page that will be used to display the report, well need to take few more steps to make this application work accordingly. 5. Create the JSP page to reference the Crystal Reports tag library, and use two of the provided tags to configure the viewer: <%@ taglib uri="/crystal-tags-reportviewer.tld" prefix="crv" %> <crv:viewer viewerName="" reportSourceType="reportingComponent"> <crv:report reportName="MasterDetail.rpt" /> </crv:viewer> 6. Configure the /WEB-INF/web.xml deployment descriptor to understand the Taglib URI reference and redirect it to the appropriate TLD tag library descriptor file: <taglib> <taglib-uri>/crystal-tags-reportviewer.tld</taglib-uri> <taglib-location> /WEB-INF/crystal-tags-reportviewer.tld </taglib-location> </taglib> After modifying the deployment descriptor, make sure to copy over the .tld file itself from C:\Program Files\Common Files\Crystal Decisions\3.0\java\lib\taglib.

When executed, the report will appear something like the following:

And when the user chooses to drill down on one particular country in the report, the viewer will change to display something similar to the following:

Scenario Conclusion
In this scenario, we created a master-detail report to show users rolled-up summarizations of data elements, and yet allowed them to drill down into the particulars of each category as the mood or need arises. Doing so provides a powerful way of allowing users to remain at a high level when first looking over a report, yet still home in on particular details when necessary, all within the same report. We also made use of the Crystal Reports XI Java Reporting Components tag library, which simplified the display of the report itself. Although the rendered display would be identical to that which would be obtained by calling the Java code directly (as we did for the Basic scenario), this approach is generally much simpler and cleaner, which is in keeping with the general philosophy of JSP. In the next scenario, we will build a report that uses reporting to produce a document, suitable for use in legal work, by exporting the reports results to Adobe Acrobat PDF format rather than HTML. In addition, well customize the data returned at runtime by passing a parameter (which well just take off of the query string, but could easily be passed in via a form instead) to the report to specify which customers current orders to display.

Deploying Crystal Reports has already been discussed to a certain degree, in that weve included the report as part of a Web applications deployment footprint by referencing the report from the webapps WEB-INF subdirectory, but other deployment considerations frequently arise and require discussion.

Database Credentials
Frequently, we wont want to store a reports database login credentials as part of the report, because either the credentials arent known at report execution time (perhaps the data returned from the report will vary depending on to whom the report is being shown) or because we want to avoid the possibility of an attacker somehow gaining access to the report file and learning passwords from it (for this reason Crystal Reports does not save database logon password in the RPT file). In these scenarios, we want to obtain the reports database credentials at runtime, and pass those in to the report before executing it. Doing so is relatively trivialpresuming that the following JSP page is the target of an HTML form that asks for the users userid and password in userid and password fields respectively, you can see that passing in database credentials to the report is as simple as creating a ConnectionInfo object, setting the username and password properties accordingly, putting it into a ConnectionInfos object, and passing that ConnecitonInfos object to the viewer before executing the report: <%@ page import="com.crystaldecisions.report.web.viewer.*, com.crystaldecisions.reports.reportengineinterface.*, com.crystaldecisions.sdk.occa.report.data.*, com.crystaldecisions.sdk.occa.report.reportsource.*" %> <% CrystalReportViewer viewer = . . .;

// set credentials information ConnectionInfo ci = new ConnectionInfo(); ci.setUserName(request.getParameter("userid")); ci.setPassword(request.getParameter("password")); ConnectionInfos connections = new ConnectionInfos(); connections.add(ci); viewer.setDatabaseLogonInfos(connections); // . . . %> When the viewer now executes, it will do so using the database credentials passed in via the indicated parameters. (It goes without saying that you need to make sure that the password field is appropriately hidden from prying eyes, probably by sending this form over HTTPS, depending on your particular network topology and security needs.) You also would want to ensure that any failed login attempts are tracked, so as to guard

against brute-force attacks against the database, one of the usual security considerations for a web application.

Passing Parameters to Reports

In some cases, a report will want to have input criteria passed into it obtained from the user rather than hard-coded within the report. Again, this can be done fairly easily by making use of the Crystal Report Viewer API, passing in Parameter objects containing the data captured from the user, usually from some form of HTML form-based input. Doing so is fairly straightforward; assuming that the user-entered data is in an HTML form field called country (indicating the Country value to use when restricting the report data to display), the following JSP code would set up the appropriate parameter to the report: <%@ page import="com.crystaldecisions.report.web.viewer.*, com.crystaldecisions.reports.reportengineinterface.*, com.crystaldecisions.sdk.occa.report.data.*, com.crystaldecisions.sdk.occa.report.reportsource.* " %>

<% CrystalReportViewer viewer = . . .;

// Passing parameters Fields fields = new Fields(); ParameterField param = new ParameterField(); param.setReportName(""); param.setName("Country"); Values vals = new Values(); ParameterFieldDiscreteValue val = new ParameterFieldDiscreteValue(); val.setValue(request.getParameter("country")); vals.add(val); param.setCurrentValues(vals); fields.add(param);

viewer.setParameterFields(fields); %> //If the parameter is on the main report, use "", otherwise if the parameter being set is on a subreport that is not linked to the main report, then enter the name of the subreport as defined in the Crystal Reports XI designer.

//If the parameter is on the main report, use "", otherwise if the parameter being set is on a subreport that is not linked to the main report, then enter the name of the subreport as defined in the Crystal Reports XI designer. Note: If the parameter is on the main report, pass "" to the setReportName() function. If the parameter is on a subreport and not linked to a parameter on the main report, pass the name of the subreport (as it was defined by the report creator in Crystal Reports) into the setReportName() method. Notice that each ParameterField can have multiple values associated with it; although not used in this scenario, this is to allow for range values to be passed in as well as specific values, such as a range of names to use (as opposed to a particular name) when querying the database. This provides a huge range of flexibility in reporting that would be difficult to create directly without complicated SQL queries.

Exporting Reports
Frankly, not everybody who reads reports adores the HTML format. HTML itself, while a powerful markup language (particularly when combined with CSS or DHTML), simply cannot provide the kind of presentation capability that many users will demand, especially when looking to print reports to paper. In these situations, it would be far better if the report could be generated to a more presentation-friendly technology, such as Adobe Acrobat Portable Document Format (PDF), or Microsoft Rich Text Format (RTF). Fortunately, Crystal Reports XI Java Reporting Component provides for such capability; in essence, the reporting component becomes a renderer of PDF and/or RTF files, rather than just HTML, and if the user has the Adobe Acrobat Plug-In or Microsoft Word Viewer installed into their browser, can browse these reports in a far richer format than just plain HTML in their client browser. Exporting a report to PDF or RTF is a matter of using a different viewer component called the ReportExportControl to execute the report against, as shown below: <%@ page import="com.crystaldecisions.report.web.viewer.*, com.crystaldecisions.reports.reportengineinterface.*, com.crystaldecisions.sdk.occa.report.data.*, com.crystaldecisions.sdk.occa.report.reportsource.*, com.crystaldecisions.reports.sdk.*, com.crystaldecisions.sdk.occa.report.lib.*, com.crystaldecisions.sdk.occa.report.exportoptions.*" %> <% ReportClientDocument oReportClientDocument = new ReportClientDocument(); oReportClientDocument.open("document1.rpt", 0); IReportSource reportSource = oReportClientDocument.getReportSource();

ReportExportControl exportControl = new ReportExportControl(); ExportOptions exportOptions = new ExportOptions(); exportOptions.setExportFormatType(ReportExportFormat.PDF);

PDFExportFormatOptions pdfexpopts = new PDFExportFormatOptions(); exportOptions.setFormatOptions(pdfexpopts);

exportControl.setReportSource(reportSource); exportControl.setExportOptions(exportOptions); exportControl.processHttpRequest(request, response, getServletConfig().getServletContext(), null); exportControl.dispose(); %> Doing so to RTF would set the export format type to ReportExportFormat.RTF, and use an RTFWordExportFormatOptions instance rather than the PDF one shown above. Note that the format options class carries a number of variables with it, such as the starting and ending page number to export. (Officially, one should use the IPDFExportFormatOptions or IRTFWordExportFormatOptions interfaces instead of their concrete subclasses, but the two, as of this writing, are one and the same).

Further Reading Justine, Im not sure if you want to include these, but heres a link to the product documentation for the JRC thats online which might be good to point customers to at the end of this guide: Crystal Reports XI Java Reporting Component Developers Reference (contains a developers guide and Javadocs for the JRC and Viewer SDK):

http://support.businessobjects.com/library/docfiles/cps10/downloads/en/crXI_Ja vaReportingComponent_en.zip

Also, once we get the official samples online, we might be able to include a link to them as well.

Summary and Conclusions

This document introduced Crystal Reports XI for J2EE applications through four common reporting scenarios. The scenarios built upon one another. Each sample report described one or more features and discussed how to implement each feature in the report. The Basic scenario created a simple report listing customers from the sample database. Report Experts did most of the work designing the report. Data was retrieved directly from the customers table, and was displayed via the Java Reporting Component (JRC) and Viewer API. Drill down capabilities was the highlighted feature in the Intermediate scenario. Drill down enables users to view the detail records that make up a summary record. This report introduced on the idea of retrieving data from views, as well as the JSP Tag library supplied with the Java Reporting Component. The Document scenario highlighted Crystals exporting features. Legal documents were created by exporting a report to PDF format and displaying the PDF data in a Web browser. This startup guide touches on many features available with Crystal Reports XI. These features are designed to ease reporting development and deployment for programmers and enhance report presentation and functionality for end users.

About the Author Citigate Hudson is a provider of custom database applications and a Microsoft Gold Certified Partner for business intelligence solutions. See their website at www.citigatehudson.com.