EspressReport for WebObjects provides seamless integration with WebObjects. It not only provides an easy way to integrate with standard EspressReportAPI by using WOComponent
classes to return dynamic pages, but also supports generating report with WebObjects’s non-java-standard collection class NSArray
. This makes it very easy for users who use enterprise objects to retrieve data.
EspressReport for WebObjects also supports advanced reporting features, such as streaming report with charts, drill-down reports, and parameterized reports.
EspressReport for WebObjects is available as separate jar file, EspressReportForWebObjects.jar
. Integrating it with your WebObjects project is very easy, just add it to your project frameworks. The source is available. You can change the source file and add them back to your project.
This chapter covers basic integration of EspressReport within a WebObjects application environment, as well as step-by-step examples for using some of the different features in EspressReport.
This section explains how to integrate some of the basic Report API functionality within a WebObjects application.
Step 1: Create a QbReport object
The following code shows how to create a QbReport
object from scratch. For more detailed information about creating report from different data sources, please refer to Section 2.3 - EspressReport Report API.
// not using EspressManager, we will use a datasource from file QbReport.setEspressManagerUsed(false); // Set up column mapping ColInfo colInfo[] = new ColInfo[14]; for (int i = 0; i < colInfo.length; i++) colInfo[i] = new ColInfo(i); // allocate the QBReport Object using the specified parameters QbReport report = new QbReport((Applet)null, QbReport.COLUMNAR, "/EspressReport/help/examples/DataSources/text/sample.dat", colInfo, null);
Step 2: Then, add more code to the above code so that the method returns a WOComponent
. The entire code for the method now looks like this:
public WOComponent returnReport() { // allocates a new WOComponent with static type WOReport // this is possible because WOReport extends WOComponent WOReport nextPage = (WOReport)pageWithName("WOReport"); QbReport.setEspressManagerUsed(false); ColInfo colInfo[] = new ColInfo[14]; for (int i = 0; i < colInfo.length; i++) colInfo[i] = new ColInfo(i); QbReport report = new QbReport((Applet)null, QbReport.COLUMNAR, "/EspressReport/help/examples/DataSources/text/sample.dat", colInfo, null); // load in the WBReport into the WOReport nextPage.setReport(report); // configure to export the report in DHTML format nextPage.setExportFormat(QbReport.DHTML); // return the WOComponent (super-class of WOReport) return nextPage; }
The class WOQbReport
extends QbReport
in the ReportAPI and is the main class used to support WebObjects. Its constructors take a NSArray
of EOGenericRecord
as data source and create reports based on it.
Before we can create a report, we need a data source to be used by the report. We will assume that we are using a Database with some EOModel mapped on top of it. The EOModel will contain a mapping of entities (tables), attributes (fields), and relationships (foreign keys) to the Database. For a review of concepts on how to setup the EOModel, please read the next section. You can safely skip this section if your understanding of the EOModel and EO Fetch Specification is strong.
he EOModel is an abstraction that separates the database layer from business logic. Using the EOModel we are able to manipulate database data as if they were Objects. After the user has setup the proper EOModel using the EOModeler, he/she will be ready to fetch data based on attributes of the EOModel.
In the EOModel, there are entities (similar to tables of SQL) and attributes (similar to columns in the tables of SQL). Entities in the EOModel are mapped to tables and views in the database. Attributes in the EOModel are mapped to columns of the tables and views in the database. In addition, the EOModel also contains relationships, which are key based logical associations among entities. It is important that the user understands the concept of Entities, Relationships, and Attributes before setting up their own EOModel. Please review the relevant topics of an EOModel before setting up your EOModel.
After we have setup an EOModel for our database, we are ready to obtain data from it. Recall that the way to obtain data as a NSArray
is by writing Fetch Specifications. An EOFetchSpecification
is an Object that specifies what are the qualifications of data we want. In a way, writing Fetch Specification for an EOModel is similar to writing a Query for the database. In fact, it is true that if we have a Fetch Specification for an EOModel, we can always write a corresponding query for a database. However, the reverse is not true. Not all queries can be written as a Fetch Specification. In this way, a Fetch Specification serves as an abstraction that helps programmers deal with data in an object oriented way, but loses the power that queries have over the control of database data.
Having said that, let’s look at an example of translating a SQL Query for a database to a Fetch Specification. Remember this is not always possible but for our example, we have restricted our task to illustrate how it can be done.
Consider a database schema with four tables: Orders
, OrderDetails
, Categories
, and Products
.
stores information about a customer order.
Attributes - OrderID
, ShipCity
, and ShipState
.
Primary Key - OrderID
details about a particular order.
Attributes - OrderID
, ProductID
, Quantity
Primary Key - ProductID
categories of product.
Attributes - CategoryID
, CategoryName
Primary Key - CategoryID
information about a product.
Attributes - CategoryID
, ProductID
, ProductName
, UnitsInStock
Primary Key - ProductID
Next, consider the query.
SELECT Orders.OrderID, Orders.ShipCity, Orders.ShipState, Categories.CategoryName, Products.ProductName, OrderDetails.Quantity FROM Orders, OrderDetails, Categories, Products WHERE Orders.ShipState = ‘NY’ AND Products.CategoryID = Categories.CategoryID AND OrderDetails.OrderID = Orders.OrderID AND OrderDetails.ProductID = Products.ProductID ORDER BY Orders.OrderID DESC, Orders.ShipCity ASC;
This query joins four tables and obtain orders that are only shipped to NY, and orders the records in descending order by the OrderID
column and orders it again in ascending order by the quantity column before returning the data records.
Now, let’s look at how to convert this SQL query to a Fetch Specification.
To have a restriction on the query, we will need to pass in an EOQualifier
object to the EOFetchSpecification
constructor. The static method qualifierWithQualifierFormat()
from EOQualifier
returns an EOQualifier
. If we simply pass in a String that is similar to a SQL Where
clause in the first argument of the qualifierWithQualifierFormat()
method, we can create a valid EOQualifier
object that restricts the data being fetched. We construct the EOQualifier
simply by including the following code:
EOQualifier qual = EOQualifier.qualifierWithQualifierFormat ("shipstate = NY", null); // we set the binding to null for simplicity
In the above code, the Where clause from the SQL Query is converted to an EOQualifier
Object by passing in a String argument. It is also possible to include AND and OR to combine one or more Boolean operators in the argument of the EOQualifier
. In addition, the EOQualifier
class also has a collection of sub-classes that are designed for other restrictions on the query. Some of these sub-classes are Boolean Qualifiers, EOAndQualifier
, EOOrQualifier
, and EONotQualifier
.
Now that we have a qualification, all we need is an ordering for the Order ID
and ShipCity
. By passing a NSArray
of EOSortOrdering
Objects to the EOFetchSpecification
Constructor, we can accomplish this task. Here is the code:
EOSortOrdering shipdateOrdering = EOSortOrdering.sortOrderingWithKey ("shipcity", EOSortOrdering.CompareAscending); EOSortOrdering orderidOrdering = EOSortOrdering.sortOrderingWithKey ("orderid", EOSortOrdering.CompareDescending); NSArray sortOrderings = new NSArray (new Object[] {shipdateOrdering, orderidOrdering});
Finally, construct the EOFetchSpecification
Object using an entity name, the previously constructed EOQualifier
, and the NSArray
of EOSortOrdering
Objects:
EOFetchSpecification fetchSpec = new EOFetchSpecification
("Orders", qual, sortOrderings);
Note | |
---|---|
Using the SQL Statement approach or the Fetch Specification approach to obtain data from the database should give the same results. |
Also note that for the Fetch Specification to work correctly, you have to set up the EOModel with the Relationship correctly defined. That is, for the joining of the identities to work automatically, you have to have joined the identities in your EOModel for the database. For information on how to use the EOModeler, please consult online documentation for the EOModeler at Apple's web site.
After an EOModel has been created, we are ready to write a fetch specification and obtain Data Objects from the Database using the EOModel. Lastly, we will use these Data Objects, in the form of a NSArray
Object, as a parameter to the WOQbReport
Constructor to create our report. The following code illustrates this concept:
EOQualifier qual = EOQualifier.qualifierWithQualifierFormat ("shipstate = 'NY'", null); EOSortOrdering shipdateOrdering = EOSortOrdering.sortOrderingWithKey ("shipcity", EOSortOrdering.CompareAscending); EOSortOrdering orderidOrdering = EOSortOrdering.sortOrderingWithKey ("orderid", EOSortOrdering.CompareDescending); NSArray sortOrderings = new NSArray (new Object[] {shipdateOrdering, orderidOrdering}); EOFetchSpecification fetchSpec = new EOFetchSpecification ("Orders", qual, sortOrderings); EOEditingContext myEditingContext = this.session().defaultEditingContext(); NSArray data = myEditingContext.objectsWithFetchSpecification(fetchSpec); String[] entities = new String[]{"Orders", "OrderDetails", "Products", "Categories"}; WOQbReport report = new WOQbReport(null, QbReport.SUMMARY, data, entities, colInfo, null);
In the above code, we first instantiated an EOFetchSpecification
Object to retrieve data from the database via the EOModel. Then fetch the data using the default Editing Context. Finally, we call the WOQbReport
constructor and pass in the NSArray
as the data source to create our report. Note that we also pass in a String array of Entity names to the constructor of the WOQbReport
. This is because we also want to display the attributes of the entities that relate to the Orders
Entity. It is also important to note that the entities OrderDetails
, Products
, and Categories
all are “related” to the Orders
entity in some type of relationship setup in the EOModel.
For an example WebObjects Project that creates a WOQbReport
using a NSArray
as the data source, please use the project EspressReportExamples in the folder <EspressReport installation dir>/help/examples/webobjects/
.
This section explains step-by-step how to integrate EspressReport into a WebObjects application using Eclipse.
Xcode is a suite of tools for developing software on Mac OS X, developed by Apple. It includes (among other things) the compiler and other necessary tools. Xcode comes with the OS X install CD (although it is not installed by default).
Eclipse is a Java IDE and the latest Eclipse application, for the Mac, can be downloaded from http://www.eclipse.org/downloads
. Before launching Eclipse, please edit <eclipse folder>/Eclipse.app/Contents/MacOS/eclipse.ini
and add the following parameters to the file in order to increase the memory and heap space of the Eclipse application:
-XX:MaxPermSize=128m
-Xmx512m
After saving the file, start Eclipse.
WOLips is a set of Eclipse tools for WebObjects development. You can download and install the plug-in (through Eclipse) by going to Available Software panel. The first time you go through this process, you will need to add the WOLips site to the list. Click on and it should pop up a new dialog. Select on the right-hand side from the dialog. In the Add Site panel that appears, enter WOLips
in the name field and enter the URL for the stable version of WOLips, http://webojects.mdimension.com/wolips/stable
, for the location field and click .
After the WOLips site is added to the list, fully expand the list to display all its offerings. Select only Standard Install. After installation, restart Eclipse.
This is an external Java program that helps programmers generate the java source for their EOs. Download the templates from http://webobjects.mdimension.com/wolips/EOGenerator/Velocity%20EOGenerator%20Templates/
and place them in the /Applications/Developing/VelocityEOGeneratorTemplates
folder.
Inside this template folder you will find two standard templates: _Entity.java
and Entity.java
. In Eclipse, select → → and enter the following information:
EOGenerator Template Folder: /Applications/Developing/VelocityEOGeneratorTemplates
EOGenerator Java Template: _Entity.java
EOGenerator Subclass Java Template: Entity.java
You are now ready to create your first WebObjects example with EspressReport.
In Eclipse, select the WOLips perspective. This is indicated in the upper right corner of the window. If you cannot find the WOLips button, click on the double right arrow at the very edge of the window and choose Other, then select the WOLips perspective from the list and click .
In WOLips perspective, CTRL+Click in the Package Explorer tab and choose . This will bring up a Select a.. window. Choose WedObjects Application under the WOLips folder from the popup dialog. When the New WebObjects Project dialog opens, enter EspressReportApp
as the name of the project, check the Use default location box to use the default workspace location, and click Next to create the project.
Clear the Base Package and Component Package fields in the next window and click Sources
, JRE System Library
, build
, Components
(and under Components
, Main WO
) and build.xml
.
Also, expand Sources and then (default package) and edit each of the java files present (Application.java
, DirectAction.java
, Main.java
and Session.java
) to remove the package .
and import .Main
lines. After editing, save the files.
In the Package Explorer, select Components/Main WO
from the tree. Click on the Component tab at the bottom of the main editor and in the HTML area (the top panel) add:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> <html> <head> <title>Untitled</title> </head> <body> <webobject name = "ReportComponent"></webobject> </body> </html>
Click in the bottom panel of the Component editor to edit the WOD file and enter
ReportComponent : WOReportComponent { }
Save the modifications.
Select EspressReportApp/Components
from Package Explorer and CTRL+Click to show a pop up dialog. Select → and then select WOComponent under WOLips. The New WebObjects Component dialog opens. Enter WOReportComponent
as the component name. Deselect Create HTML contents and Create api file and click .
You should see a new WOReportComponent.java
in your source folder and a WOReportComponent WO
folder at the Components folder. Select WOReportComponent WO
from Package Explorer tree and switch to the component tab. Type in the following in HTML panel (UPPER PANEL):
<webobject name = "ReportComponent"></webobject>
Then, type the following in the WOD definition window (LOWER PANEL) and save:
ReportComponent : WOEmbeddedObject { value = reportComponent; width = 1500; height = 1800; }
CTRL+Click on the EspressReportApp
folder from Package Explorer tree and select Properties from the popup menu. Then click on Java Build Path from the left side in the new popup dialog. Select Add External Jars and browse and add EspressReportForWebObjects.jar
, ReportAPIWithChart.jar
, hsqldb.jar
and qblicense.jar
from the <EspressReport Install Directory>/lib
folder.
Drag ParameterizedNSArray.java
and WOReportComponent.java
from the <EspressReport Install Directory>/help/examples/WebObjects
folder to EspressReportApp/Sources/(default package)
in package explorer.
Click on the WOReportComponent.java
file underneath the Sources folder and modify path to sample.dat to point to <EspressReport Install Directory>/help/examples/DataSources/text/sample.dat
.
CTRL+Click on the project name and select → . Choose Application - (default package) in the Select Java Application dialog and click . Then you should see a report which displayed in your default web browser.
CTRL+Click on EspressReportApp/build/EspressReportApp.woa/Contents/Resources
and select New: Other. Select EOModel from WOLips folder in the popup dialog. Enter WoodView
for the EOModel name and choose JDBC for Adaptor type. Please make sure Use EOGenerator File is checked and click . Switch to the Entity Modeler Prespective.
In the Entity Modeler, select Outline from the left tabbed panel, expand WoodView folder. Select Default and click on Properties in the bottom panel below. Fill in the username (sa
) and password (leave it blank). For URL, enter jdbc:hsqldb:<EspressReport Install Directory>help/examples/DataSources/database/woodview and for Driver, enter org.hsqldb.jdbcDriver
.
Click on Basic Tab in the Properties pane and change the new entity's name to Orders
, the table name to Orders
and set the class name to com.EspressReportApp.eo.Orders
.
Name: OrderDetails Table Name: Order_Details Class Name: com.EspressReportApp.eo.OrderDetails Name: Categories Table Name: Categories Class Name: com.EspressReportApp.eo.Categories Name: Products Table Name: Products Class Name: com.EspressReportApp.eo.Products
Select the Orders
entity and click on the New Attribute from the toolbar button. After a new attribute is created, select the Properties pane and enter the following:
Name: orderid Column: OrderID External Type: INTEGER Data Type: Integer - Integer Key icon (Primary Key): checked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked
Repeat the above steps to create the following attributes for the Orders
entity:
Name: shipcity Column: ShipCity External Type: CHAR Data Type: String - String S External Width: 50 Key icon (Primary Key): unchecked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked Name: shipstate Column: ShipState External Type: CHAR Data Type: String - String S External Width: 50 Key icon (Primary Key): unchecked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked
Add the following attributes for the OrdersDetails
entity:
Name: orderid Column: OrderID External Type: INTEGER Data Type: Integer - Integer Key icon (Primary Key): unchecked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked Name: productid Column: ProductID External Type: INTEGER Data Type: Integer - Integer Key icon (Primary Key): checked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked Name: quantity Column: Quantity External Type: INTEGER Data Type: Integer - Integer Key icon (Primary Key): unchecked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked
Select the entity Categories
and create the following attributes:
Name: categoryid Column: CategoryID External Type: CHAR Data Type: String - String S External Width: 50 Key icon (Primary Key): checked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked Name: categoryname Column: CategoryName External Type: CHAR Data Type: String - String S External Width: 50 Key icon (Primary Key): unchecked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked
Add the following attributes for the Products
entity:
Name: categoryid Column: CategoryID External Type: CHAR Data Type: String - String S External Width: 50 Key icon (Primary Key):un checked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked Name: productid Column: ProductID External Type: INTEGER Data Type: Integer - Integer Key icon (Primary Key):checked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked Name: productname Column: ProductName External Type: CHAR Data Type: String - String S External Width: 50 Key icon (Primary Key):un checked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked Name: unitsinstock Column: UnitsInStock External Type: INTEGER Data Type: Integer - Integer Key icon (Primary Key):un checked Diamond icon (Class Property): checked Lock icon (Used for Locking): checked
CTRL+Click on Orders
and select New Relationship from the popup menu. The Create New Relationships dialog opens. Map Woodview.Orders
and Woodview.OrderDetails
together.
In left panel From Orders…, select to many OrderDetails, check the checkbox for write a new relationship named and uncheck the checkbox for foreign key. In right panel From OrderDetails…, select to one Orders, check the checkbox for write a new relationship named and uncheck the checkbox for foreign key. At the Joins panel, map Orders.orderid
and OrderDetails.orderid
together and click .
CTRL+Click on OrderDetails and select New Relationship from the pop up menu. Map Woodview.OrderDetails
and Woodview.Products
together.
In left panel From OrderDetails…, select to one Products, check the checkbox for write a new relationship named and uncheck the checkbox for foreign key. In right panel From Products…, select to many OrderDetails, check the checkbox for write a new relationship named, and uncheck the checkbox for foreign key.
At the Joins panel, map OrderDetails.productid
and Products.productid
together and click
CTRL+Click on Products" and select New Relationship from the popup menu. Map Woodview.Products
and Woodview.Categories
together.
In left panel From Products…, select to one Categories, check the checkbox for write a new relationship named and uncheck the checkbox for foreign key. In right panel From Categories…, select to many Products, check the checkbox for write a new relationship named and uncheck the checkbox for foreign key.
At the Joins panel, map Products.categoryid
and Products.categoryid
together and click
After creating the entities, attributes and relationships, click the
button from the toolbar. The window should come up with no errors message.Select the
button from the toolbar to save the view model.Delete the woodview.ecogen
file (if it exists) from EspressReportApp/build/EspressReportApp.woa/Contents/Resources
. CTRL+Click on the WoodView
EOModel from the package explorer and select → from the pop up menu. CTRL+Click on the generated woodview.ecogen
and select EOGenerate from the popup menu. It should return without any errors and you should see new java files created under the Sources folder.
Select WOReportComponent WO from Package Explorer tree and switch to the Component tab. In the WOD definition window (LOWER PANEL), replace the value
attribute to generateReportFromNSArray
ReportComponent : WOEmbeddedObject { value = generateReportFromNSArray; width = 1500; height = 1800; }
CTRL+Click the project, EspressReportApp, in the Package Explorer pane and select → from the popup menu. As before, choose Application - (default package) from the list. The report should pop up from your default web browser.
Select WOReportComponent WO from Package Explorer tree and switch to the Component tab. In the WOD definition window (LOWER PANEL), replace the value attribute to generateParamNSArrayReport
ReportComponent : WOEmbeddedObject { value = generateParamNSArrayReport; width = 1500; height = 1800; }
CTRL+Click the project, EspressReportApp, in the Package Explorer pane and select → from the popup menu. Again, choose Application - (default package) from the list. You will then get prompted by the parameter input dialog. Type in NY
for the city and click . The report should popup from your default web browser.
All files (those in the EspressReportsForWebObjects.jar
file and the two additional files) are located under <EspressReport Install Directory>/help/examples/WebObjects
folder.
Note | |
---|---|
By default, EspressManager is not used. If you want to have EspressManager up and running, you will need to modify the source code to suit your needs. If EspressManager is not running for drill-down reports, reports with a sub-report, or reporta with A chart, you will need to specify the path using the following methods:
|