In this article, you will learn how to use the Jakarta Element Construction Set (ECS), a set of Java classes that you can use to develop applications that generate well-formatted markup documents. I'll walk you through the process of downloading and using the ECS libraries to develop a sample application that can read various log files and generate a status report in HTML format from them. I won't go into the details of the application that generates the log files; instead, I'll just assume that the application uses a standardized format for its log files. (Of course, you can use the ECS libraries with various log file formats that are different from the format we'll use here, though you would need to modify the parsing algorithm for extracting the required information from log files accordingly.) You could write similar code or a plugin to convert your own streamed or complex logs into well-formatted HTML files for better readability and easier use.
Large enterprise applications -- like application servers, testing applications, or online systems with transactional logging -- generate a huge number of log files. Reading the complete log and extracting a summary of useful data can be difficult and time-consuming. An HTML-formatted summary report can present the data in a more readable way. But the generation of a large HTML file within a Java application is another tough job. The example we'll examine together offers a simple and manageable approach for generating HTML documents using the Jakarta ECS API. The techniques that we'll use can be extended to any application requiring the generation of markup documents.
ECS is a set of classes that can be used to generate documents written in HTML, XML, VoiceXML, and other markup languages. Currently, ECS supports HTML and XML, but it can be extended to support various other markup languages. With ECS, you can create an application that generates such documents using an object-oriented approach; this eases application development and maintenance. ECS provides you with a more manageable technique for generating markup code using Java objects.
The traditional way to create HTML documents
In a typical scenario, how would a developer write Java code that creates HTML documents? Generally, a servlet would write a response back to the client. The code in Listing 1 illustrates a common approach in such an application.
Listing 1. Code to generate HTML within a Java application
out.println("<HTML>");
out.println("<HEAD><TITLE>Log Report</TITLE></HEAD>");
out.println("<BODY>");
out.println("<H1>Logs for application A</H1>");
out.println("<H3>Generated on Mar 03rd, 2004</H3>");
out.println("Following table lists down status of all testcases.");
out.println("</BODY>");
out.println("</HTML>");
|
This kind of code is difficult to debug, modify, and manage. Moreover, here you must handle the formatting of the markup that is output. HTML documents don't always need to be well-formed, but if you're trying to create XML documents, code like that shown in Listing 1 becomes a programmer's headache: the code deals in Strings and does not use any feature of the markup language. The programmer has to make sure that tags are properly closed and nested. As you'll see, ECS wisely does all this for you.
Now let's look at an alternate approach that uses the ECS APIs. The code in Listing 2 creates the same HTML document that the code in Listing 1 creates. If you look at it closely, you will see that it saves you the hassle of writing code that outputs special characters like < and >.
Listing 2. Code to generate HTML within a Java application using ECS
Html html = new Html()
Head head = new Head();
head.addElement(new Title("Log Report")));
html.addElement(head);
Body body = new Body();
body.addElement(new H1("Logs for application A"));
body.addElement(new H3("Generated on Mar 03rd, 2004"));
body.addElement("Following table lists down status of all testcases.")));
html.addElement(body);
out.println(html.toString());
|
Programmers will appreciate the neat and object-oriented method of generating HTML illustrated in Listing 2. Here, every HTML element in your final document is a Java object. You embed objects within other objects to form nested HTML code. You are dealing with Java objects rather than raw string data to form an HTML document. ECS accepts names for added elements -- a concept similar to that of a key in java.util.Hashtable. You can access elements using this key later and can even remove elements. Modifying or removing HTML elements in the earlier approach was almost impossible because of the lack of any structure.
For complex documents, ECS comes in handy, because it has classes defined to manage colors, documents, and more.
ECS provides a programmatic way to generate documents written in various markup languages. It is designed so that all tag generation takes place through object-oriented abstraction.
The ECS structure is defined in such a way that the Document class, which creates a document container, acts like a wrapper for the Html, Head, Title, and Body elements. In fact, ECS has a Java class that corresponds to each HTML tag. For example, Html.class corresponds to the <html> tag, Head.class to the <head> tag, and so on. The tags can be created and added using the corresponding Java objects. Figure 1 represents the object layout, showing the ECS classes' container relationship.
Figure 1. Element structure
ECS defines a set of classes and interfaces, illustrated in Figure 2.
Figure 2. Class structure
Before I get to the sample application, I'll discuss some of the more commonly used ECS classes. This will help you better understand the sample code.
org.apache.ecs.html.Html
This class represents the <html> element in HTML. This type of object is used for accommodating all the rest of the elements. All other element objects are included in it or in one of its children.
org.apache.ecs.html.Head
This class represents the <head> element in HTML.
org.apache.ecs.html.Table
This class represents the <table> element in HTML. The attributes of this HTML element (like border, bgcolor, cellspacing, etc.) can be set using the getter/setter methods of this class.
org.apache.ecs.html.Form
This class represents the <form> element in HTML. The attributes of this HTML element (like action, name, method, etc.) can be set using the getter/setter methods of this class.
org.apache.ecs.html.Body
This class represents the <body> element in HTML. The attributes (like background, alink, bgcolor, etc.) and events (like onClick, onDblClick, onKeyPress, etc.) of this HTML element can be set using the getter/setter methods of this class.
A sample log-generating application
In this section, I'll review the highlights of the code for the sample application and explain how it works. If you want to see the complete application code as well as the sample log files the application will be parsing, you can click on the Code icon at the top or bottom of this article. After the code review, I'll walk you through the process of downloading the sample code and the ECS libraries so that you can execute the example application on your own machine if you wish.
To set the stage for the walkthrough, imagine that you use an application that executes various test cases and generates individual log files for each case. (The nature of this application isn't really important for our purposes.) The test cases have one thing in common: the format of their log files. Listing 3 shows a sample log file. Though this file is relatively simple, longer log files can be very complex and cumbersome to read and analyse.
Listing 3. Log file
Testlog for Tc1 *************** Variation 1 : Passed Variation 2 : Passed Variation 3 : Passed SUMMARY -> Total variations : 3 Total variations ran : 3 Total Passed : 3 Total Failed : 0 Testcase Result : PASSED |
The first line indicates that this test log is for the test case named Tc1. The next three lines show variations in the test case: there are three of them, and all have passed. The summary of the run of this test case appears after the SUMMARY -> line.
Now that you've seen the log files that we'll be dealing with, we will write a Java application that parses these files and generates a consolidated report. The first step is to create the root element, <html>, as shown in Listing 4:
Listing 4. Creating the <html> element
Html html = new Html();
Head head = new Head();
Title title = new Title("Logging in HTML format");
head.addElement(title);
html.addElement(head);
|
In this code, Html is the object that will encapsulate the whole of the document. The next subelement is <HEAD>, which is represented by the Head class here. The <TITLE> element is represented by the Title class. The value between the starting and ending <TITLE> tags is passed as argument to the constructor of the Title class. This Title element is added to Head, and Head is added to Html.
The next step is to read and parse the log files to gather the information you need. The code extracts the name of the test case, the total variations to be run, the total variations that ran, the number of variations that passed, the number of variations that failed, and the path of the log file, and stores all of that information in Log objects. While parsing a series of log files, the code creates a Vector of Log objects, with one Log object per log file. If you're interested in the logic for all this, you can examine the code in ecs.jar; it's not really that important for the bigger picture, as the logic is specific to the format of the log file.
So, now you have a Vector of Log objects, with each Log representing one log file. The Log class has the structure illustrated in Listing 5.
Listing 5. Log class
public class Log
{
private String testcaseName = null; // Name of the testcase
private int totalVariations = 0; // total number of variations in it
private int totalRan = 0; // total variations ran
private int totalPassed = 0; // total variations passed
private int totalFailed = 0; // total variations failed
private String result = null; // result of the testcase
private String logFile = null; // path of the log file
public String getResult() {}
public String getTestcaseName() {}
public int getTotalFailed() {}
public int getTotalPassed() {}
public int getTotalRan() {}
public int getTotalVariations() {}
public String getLogFile(){}
public void setResult(String string) {}
public void setTestcaseName(String string) {}
public void setTotalFailed(int i) {}
public void setTotalPassed(int i) {}
public void setTotalRan(int i) {}
public void setTotalVariations(int i) {}
public void setLogFile(String string) {}
}
|
Now that the log files have been parsed and you have all the data we need for generating the report, the previously complex and confusing task of printing well-formatted reports can be achieved easily with ECS. In Listing 6, I'll show you how to create a table structure in which each column represents a corresponding attribute of the Log class. In the table, there is a row for each test case.
Listing 6. Table headers
Table table = new Table();
table.setBorder(1);
TH th = null;
String[] tableHeaders =
{
"Serial Number",
"Testcase Name",
"Total variations",
"Total variations ran",
"Total Passed",
"Total Failed",
"Result",
"Log File" };
for (int j = 0; j < tableHeaders.length; j++) {
th = new TH(tableHeaders[j]);
table.addElement(th);
}
|
Once the table is created and populated with its table headers, you need to generate the table data. For this, you iterate over the Vector and generate <TR> tags, one for each log file. In Listing 7, logs is the Vector that contains Log objects.
Listing 7. Generating table rows
TR tr = null;
TD td = null;
Font font = null;
Iterator it = logs.iterator();
int count = 1;
while (it.hasNext()) {
Log log = (Log) it.next();
String testcaseName = log.getTestcaseName();
int totalVariations = log.getTotalVariations();
int totalPassed = log.getTotalPassed();
int totalFailed = log.getTotalFailed();
int totalRan = log.getTotalRan();
String result = log.getResult();
String logFile = log.getLogFile();
tr = new TR();
tr =
createTR(
count++,
testcaseName,
totalVariations,
totalRan,
totalPassed,
totalFailed,
result,
logFile);
table.addElement(tr);
}
|
Note that the createTR() method is defined within the complete source code, but not illustrated here to save space; take a look at the code to see how it works.
This step completes the required <TABLE> structure, which is now ready to be included in the <BODY> element. Now the final task is to include this <TABLE> element in the <BODY> object and save all of the HTML code to a file, which you'll do in Listing 8.
Listing 8. Saving HTML in a file
body.addElement(table);
html.addElement(body);
DataOutputStream output = null;
try {
output =
new DataOutputStream(new BufferedOutputStream(new FileOutputStream("./result.html")));
output.write(html.toString().getBytes());
} catch (Exception e) {
e.printStackTrace();
}
|
The code in Listing 8 saves the HTML code generated in your application to a file named result.html in the current directory.
Running the sample application
Before you can run the sample application, you must download the required ECS libraries and set up your environment to accomodate them. Follow these steps:
- Download the latest version of ECS. (ecs-1.4.2.zip was the current version at time of publication.)
- Save the file locally (at C:\ecsapi\ecs-1.4.2.zip, for instance).
- Set your classpath to include C:\ecsapi\ecs-1.4.2.zip.
Note that if you are working within an IDE, you'll need to set its classpath as well. Some IDEs pick up only their internally set classpath.
Now you can install the sample application itself:
- If you haven't done so already, download the source for this article, ecs.jar, by clicking on the Code icon at the top or bottom of this article.
- Unzip ecs.jar in a folder. Using C:\ecs as an example; unzipping the JAR extracts the class files to C:\ecs and log files to C:\ecs\com\ecs\log.
- Set your classpath to include C:\ecs.
- Run the application as
java com.ecs.log.GenerateReport C:\ecs, which will generate result.html in current directory.
Figure 3 illustrates the generated HTML.
Figure 3. Program output
In this article, you've learned about the architectural components of the Jakarta ECS and how to use it to generate a well-formatted HTML status report from log files using Java objects. However, this library's usefulness doesn't end there. There are many other potential applications of ECS:
- Consider a database system that has the capability to generate data in XML format. Such a database could use ECS to extend the types of markups it could generate for data.
- Imagine a scenario in which a DBA recieves requests for changes to a database remotely. He or she can access and modify the database using a PDA. ECS can be leveraged to generate the WML interface that the DBA would work with.
- Suppose you have an application that could use a browser, a Web service, a PDA, or a phone as a client. In such a case, an application factory could choose the appropriate markup for each client type (HTML, XML, WML, or VoiceXML, respectively) and generate it using ECS.
As you can see, ECS can come in handy in any situation in which you need to programmatically generate markup. I hope that this article has offered you some insight into this useful technology.
| Name | Size | Download method |
|---|---|---|
| j-ecs.jar | 8KB | HTTP |
Information about download methods
- The Jakarta ECS home page is a repository of ECS documentation.
- Download the Jakarta ECS Binaries.
- Learn more about Rational Rose, which generated the class diagram in Figure 2.
- Find hundreds more Java technology resources on the developerWorks Java technology zone.
- Browse for books on these and other technical topics.
Amit Tuli is a software engineer with IBM India Research Lab, New Delhi. He is currently working on the IBM WebFountain toolkit. He has four years of technical experience in Java language and C++ server-side programming on multiple platforms, and has worked with relational database systems like DB2 UDB and Oracle. His areas of expertise include designing and developing stand-alone to n-tier distributed applications. He holds a master's degree in computer applications from the GJ University in Hisar. Contact Amit at tamit@in.ibm.com.




