Incorporating DataVision Into a Java Application
It isn't difficult to incorporate DataVision into a Java application.
Instantiate a Report object and have it read the XML file and possibly a
parameter value XML file, then give the report object a layout engine
object (such as LaTeXLE).
To run a report from a JSP page, see Running DataVision
from JSP below.
To run your application you will need to include in your classpath the five
JAR files that are in the lib directory. They include
- DataVision,
- MinML2, the XML parser written by John Wilson,
- JCalendar, the calendar Swing widget by Kai Toedter,
- JRuby, and
- The GNU Java regex library.
Here is the code you need to run a report from within your application.
First, we will present some code chunks interspersed with insightful
commentary. A few complete examples, showing different data sources and
layout engines, will round out this section.
Creating a report object
First, create a report object.
Report report = new Report();
Specifying a database data source
What happens next depends upon the data source that the report XML file
describes. If it's a database, we have to give some information (the
database password) to the report before we read the XML file. If the data
source is a text file, we need to specify some things after the XML file is
read and the data source object is created.
The report's connection to a database can be specified one of three
ways. You can supply a database password, a
java.sql.Connection object, or a
jimm.datavision.sql.Database object.
If you supply a password, the XML file's database connection information
will be used to create a new connection. This is what normally happens when
you open a report via the GUI, for example.
Both of the other methods (supplying a connection or database object)
ignore the database connection information in the report XML file. If you
supply a connection it will not be closed by the report, even if
the report's database connection is reset by calling
Database.reset. You will have to close the connection yourself
after the report is done running.
The only reason you would supply a
jimm.datavision.sql.Database object is to reuse one between
different report instances. The advantage of reusing a database object is
that the database metadata (table names, column names, and more) will only
be read once no matter how many reports use it. Reading the metadata is
time-consuming.
// Give the report enough information to connect to a database
// data source. Pick one of the following three lines.
report.setDatabasePassword("mypassword");
// or
report.setDatabaseConnection(aJdbcConnection);
// or
report.setDataSource(new Database(...));
Reading the report description XML
file
Next, call Report.read (formerly called
readFile) to read a report's description XML. This method can
take as an argument a file name, a java.io.Reader, a
java.io.InputStreamReader, or an
org.xml.sax.InputSource. The InputSource
constructor can take a java.io.InputStream, a
java.io.Reader, or a String that specifies a
system identifier. If the system identifier is a URI (a URL), it must be
fully resolved.
// Read the report XML from a file or various stream types.
report.read(xmlFileNameOrStream); // Must be after database info
Specifying a text file data source
If the data source is a text file instead of a database, we need to tell
the data source which file to read and optionally override the separator
character specified in the XML file. If no character is defined in either
the XML file or your code, the default character (comma) is used.
The method CharSepSource.setInput can take as an argument a
file name, a java.io.Reader, or a
java.io.InputStreamReader.
CharSepSource src = (CharSepSource)report.getDataSource();
src.setSepChar('\t'); // Optional; overrides default and XML file value
src.setInput(fileNameOrStream);
Reading parameter values
If necessary, read parameter values. The method
Report.setParameterXMLInput (formerly called
setParameterXMLFile) is used to read parameter values from
XML. This method takes the same arguments as Report.read,
described above.
// If necessary, read parameter values.
if (report.hasParameterFields())
report.setParameterXMLInput(paramXMLFileNameOrStream);
Setting the layout engine
Next, give the report a layout engine. This example uses the LaTeX
layout engine. You could use HTML, PDF, Swing, or any other one.
report.setLayoutEngine(new LaTeXLE(aWriter));
Running the report
Finally, run the report either in a separate thread or in the current
thread. Report.run runs the report in a separate thread. It
does not wait for the thread to finish. You will have to write the code to
wait. If you call Report.runReport, the report is run
synchronously; the method does not return until the report is done
running.
// Pick one of the following two.
report.run(); // Run the report in a separate thread.
// or
report.runReport(); // Run the report in this thread.
Telling a Swing layout engine to
exit
If you use a Swing layout engine, there is one more thing you may want
to do: exit. When the user closes the Swing report window, the application
does not automatically quit---the event loop keeps running.
The SwingLE layout engine has a method called
close. It does not exit the application, but we can create an
anonymous class that overrides that method and closes the application when
the window is closed. Here's how:
LayoutEngine le = new SwingLE() {
public void close() {
super.close();
System.exit();
}
};
report.setLayoutEngine(le);
Similarly, when the last design window is closed DataVision normally
exits. The method DesignWin.setExitWhenLastWinClosed does what
it says: it lets you determine if DataVision should exit when the last
design window is closed.
All together now
Here's the whole thing all together. This code will run a report that
uses a database connection to read data, reads the report XML file, reads a
parameter file if necessary, and outputs to a PDF file.
Report report = new Report();
report.setDatabasePassword("mypassword");
report.read("reportXmlFile");
if (report.hasParameterFields())
report.setParameterXMLInput("paramXmlFile");
PrintWriter out = new PrintWriter(new FileWriter("output.pdf"));
report.setLayoutEngine(new PDFLE(out));
report.runReport();
Asking for Parameter Values
There are two ways a report gets parameter values: either by asking the
user or by reading a parameter XML file. If you want the user to be
prompted for input, you should not give the report a parameter file name.
Instead, you should tell the system that you want to use a Swing window to
prompt the user for parameter values by using the following code some time
before running the report:
ErrorHandler.useGUI(true);
When a report runs, it asks itself, ``Do I have any parameters that need
values?'' If the answer is yes, it then asks itself, ``Am I using a GUI?''
If the answer to that question is ``yes'', it opens a Swing window to ask
the user for parameter values. If the answer is ``no'', it reads the
parameter XML file you gave it on the command line or from your code (see
the previous section's example code).
To specify a parameter file on the command line, use the -r
command line option. See Running
DataVision from the Command Line for details.
To specify a parameter's value within your code, you need to ask the
report object to find it and then set its value. Note we are talking about
setting individual parameter values manually instead of reading them from
an XML file or input stream.
// Ask the report to find the parameter for you
Parameter p = report.findParameter(new Long(myParamID));
// or p = report.findParameterByName("My Parameter Name");
// Set the parameter's value. This sets a single value.
p.setValue(0, "The New Value");
// To set more values (if it is a range or a list of values), keep
// calling setValue().
// p.setValue(1, "Another Value");
Now, the tricky part: telling the report that it does not have to read a
parameter XML file or ask the user for values. My untested
suggestion: create a subclass of Report and override
askForParameters. In that new method, set the parameter values
and then tell the report that you are done.
protected void askForParameters() {
// Ask the report to find the parameter for you
Parameter p = findParameter(new Long(myParamID));
// Set the parameter's value. This sets a single value.
p.setValue(0, "The New Value");
// The next two lines are necessary.
askedForParameters = true;
parametersHaveValues = true;
}
Running DataVision from JSP
You can run a report in a JSP page, but you can't display its output
directly, even if you use the HTML layout engine. You need to save the
output to a (possibly temporary) file and then display the contents of that
file or let the user download it.
For an example JSP page, see datavision.jsp in the
examples directory. The comment at the top of that
file contains directions for installing and running it from Tomcat.
Running DataVision as an Applet
DataVision can be run as an applet. The file applet.html
contains an example ``applet'' tag suitable for use with DataVision.
The applet code is still under development; expect some
problems.
In the example file applet.html, the ``archive'' attribute
does not contain a database JAR file or jcalendar.jar. To run
reports instead of just design them, you would have to add your JDBC JAR
file and jcalendar.jar to this list. Why aren't those files in
the list already? Because the applet code is being developed first to allow
report design. Running reports should work; I just haven't tested it yet.
Since JRuby uses a custom class loader, you will have to either sign the
applet or edit the client's java.policy file and add the line
permission java.lang.RuntimePermission "getClassLoader";
Many thanks to Edwin Ramirez, who has funded development of
DataVision in order to create the applet code. All of his suggestions and
feature requests have been folded into DataVision.