In the
previous topic, we showed how to print the contents of the WebSphere Application Server thread pool data structures, but with a rather primitive formatting (one line per field, no titles, a simple blank like to separate groups of fields). Let's add some more sophisticated constructs to provide a better format for the output:
public class WASThreadPoolsSample2 extends WASAnalyzerBase implements IReport { public IAnalysisReport produceReport() {
IAnalysisReport out = allocateReport(null);
ObjectWrapperCollection pools = ObjectWrapperCollection.getObjectInstances(getContext(), "com/ibm/ws/util/ThreadPool");/*NEW*/ out.printField("Number of thread pools", pools.size()); for (int index = 0; index < pools.size(); index++) {
ObjectWrapper pool = (ObjectWrapper) pools.get(index);/*NEW*/ out.startSection("Thread Pool", IAnalysisReport.TAG_STANDOUT); { pool.printValueAtPath(out, "Pool name", "name");/*NEW*/ out.startFormatSection(IAnalysisReport.FORMAT_COLUMNS, "1 1"); {
pool.printValueAtPath(out, "Min size", "minimumPoolSize_");
pool.printValueAtPath(out, "Max size", "maximumPoolSize_");
/*NEW*/ } out.endSection(); pool.printValueAtPath(out, "Current size", "poolSize_");
pool.printValueAtPath(out, "List of Threads", "threads_");/*NEW*/ } out.endSection(); }
return out;
}
}
Here is a fragment of the output:
Number of thread pools: 14Thread Pool:
Pool name: "ORB.thread.pool"
Min size: 10 Max size: 50
Current size: 0
List of Threads: java/util/HashMap@0x00AA7B98
Thread Pool:
Pool name: "HAManager.thread.pool"
Min size: 2 Max size: 2
Current size: 1
List of Threads: java/util/HashMap@0x0102D520...
The key aspects are as follows:
The
printValueAtPath() method in
ObjectWrapper is excellent for printing the value of some field within a particular object instance from the dump. But what if we want to print in the report a value that does not come directly from an object's field, but that is computed during the analysis itself (for example the sum of two fields), or, as in this example, the number of entries in the collection of objects obtained through
ObjectWrapperCollection.
The construct to use in this case is:
out.printField("Number of thread pools", pools.size());
The
printField() method, implemented by the report object, is similar to
printLiteral(), but it takes an arbitrary value (integer, String, etc.) as an argument and prints that value.
One might be tempted, rather than using
printField(), to simply dynamically generate a string containing the desired value and pass it to
printLiteral(). This should be avoided, and
printLiteral() should be used only with constant strings (literals). This is because:
- the label and value might not be formatted properly in all the output formats supported by the Dump Analyzer tool
- the label might not be translated (when using some options to translate the report)
- automated tools that parse reports (in XML) to extract values might not be able to extract that value
In the previous example, we used a simple blank line generated with
printLiteral("") to separate different groups of related items, such as the information relative to each of the thread pool objects. A more flexible way to do this is to use the
sections facility of the report object:
out.startSection("Thread Pool"); {
// ... some contents for the report, as the body of this section
} out.endSection();
Each section has a title, and its body is formatted in the output in a way that makes it clear that it belongs under the title of this particular section, and distinct from other parts of the report that are not within that section. Typically, this is accomplished by indenting the body of the section under its title, but there might be other typesetting tricks used in other output formats.
The
TAG_STANDOUT option further refines how the section is presenting, by forcing some white space (blank lines) to separate it from adjacent sections.
Sections may be nested inside other sections to an arbitrary depth to provide a complex structure for a report. In fact, most long reports consist of many sections following each other and/or nested within each other.
Notes:
- Additional formatting options are available to refine how sections are presented in the output. For example, the TAG_MAJORHEADING option causes the section's title to be rendered as a major heading in the overall report, possibly in a larger font, bold, and numbered. See the API documentation for the IAnalysisReport interface for details.
- All startSection() calls must have a matching endSection(). If there is a mismatch, you will get an error at runtime when generating the report. The "trick" used above to add an anonymous Java™ code block for the body of each, is convenient to help see these mismatched sections at compile time rather than runtime.
Beside the ability to group related fields into sections as described above, the report object also provides some mechanisms to control how various fields are presented. The most commonly-used is to put several fields onto a single line, instead of having each field on its own line:
out.startFormatSection(IAnalysisReport.FORMAT_COLUMNS, "1 1"); {
pool.printValueAtPath(out, "Min size", "minimumPoolSize_");
pool.printValueAtPath(out, "Max size", "maximumPoolSize_");
} out.endSection();
With this construct, the two fields "Min size" and "Max size", which constitute the body of the
startFormatSection() block are shown in two columns on a single line.
Notes:
- Note that FORMAT_COLUMNS does not behave quite as one might expect by comparison with, for example, the HTML table facility. Each startFormatSection(...FORMAT_COLUMNS...) block must represent a single line in the report output. If you want to generate a multi-row table, you must repeat the startFormatSection(...FORMAT_COLUMNS...) once for each row.
Printing Groups of ObjectWrapper Fields