[go: up one dir, main page]

0% found this document useful (0 votes)
148 views68 pages

(Java Developers Journal 2004-8 Vol. 9 Iss. 8) - (2004)

Jornal para desenvolvedores em Java, datado no ano de 2004. @j_de_jotinha

Uploaded by

Jonathan Santos
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
148 views68 pages

(Java Developers Journal 2004-8 Vol. 9 Iss. 8) - (2004)

Jornal para desenvolvedores em Java, datado no ano de 2004. @j_de_jotinha

Uploaded by

Jonathan Santos
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 68

THE NETWORK EFFECT: J2EE AND .

NET PG 66
No. 1 i-Technology Magazine in the World
Feature:

Using
Apache C
Tting se
actus
rver-side
componen
ts
page 28

AUGUST 2004 VOLUME:9 ISSUE:8


ISSUE:

Dynamic Sorting with Java

Unlocking Microsoft
RETAILERS PLEASE DISPLAY PLUS... Office Documents
UNTIL OCTOBER 31, 2004

Walking the Tightrope of Embedding the Java Virtual Machine,


Microsoft-Java Interoperability Once and for All
The Blind Men, the Elephant, Web Conferencing Using the
and App Server Migration Java Media Framework
T H E W O R L D ’ S L E A D I N G i -T E C H N O L O G Y M A G A Z I N E W W W. S Y S - C O N . C O M / J D J
Oracle Platform

Database 10g
Application Server 10g

Common LDAP directory

Unified security model

Common administration

Automated space management

Engineered to work together

oracle.com/platform
or call 1.800.633.0753

Copyright © 2004, Oracle Corporation. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates.
From the Group Publisher

Editorial Board
Putting the ‘i’
Back in i-Technology
Desktop Java Editor: Joe Winchester
Core and Internals Editor: Calvin Austin
Contributing Editor: Ajit Sagar Jeremy Geelan
Contributing Editor: Yakov Fain
Contributing Editor: Bill Roth
Contributing Editor: Bill Dudney

E
Contributing Editor: Michael Yuan
Founding Editor: Sean Rhody ver since Nicholas G. Carr’s Inc., seems likely to be as high as $36
now historic Harvard Business billion, rivaling corporate IT stalwarts
Production Review article, “IT Doesn’t Mat- such as McDonald’s Corp. and Sony
Production Consultant: Jim Morgan
ter,” published in the May 2003 Corp? Search is still very much the new
Associate Art Director: Tami Beatty–Lima
Executive Editor: Nancy Valentine edition of HBR, it was only a matter of frontier so far as the Internet is con-
Associate Editors: Jamie Matusow time before the wider world caught up cerned. How else can you account for
Gail Schultz
with Carr’s thesis. The article formed the growth of storage giants like EMC
Jennifer Van Winckel
Assistant Editor: Torrey Gaver only a small part of Carr’s broader ex- and security giants like Cisco, which as
Online Editor: Lin Goetz ploration of the influence of informa- long ago as 2000 was being labeled “the
Research Editor: Bahadir Karuv, PhD
tion technology on business strategy quiet security giant” as the undisputed
contained in his book Does IT Matter? king of switches and routers began
Writers in This Issue Information Technology and the Cor- rapidly to make a name for itself in the
Ryan Ackley, Calvin Austin, York Davis,
Jeremy Geelan, Ted Goddard, Gunnar Grim, rosion of Competitive Advantage, but it security arena?
Rob Halleron, Michael Havey, Pramod Jain, is the “IT Doesn’t Matter” chapter that Without the Internet and the tech-
Yayati Kasralikar, Kishore Kumar, Heman Robinson,
Ajit Sagar, Avik Sengupta, Derek Spratt, sticks in everybody’s mind. nologies related to it there would be no
Stanley Wang, Joe Winchester
In it, Carr argued that while IT U.S. stock market uptick in process. So
To submit a proposal for an article, go to
http://grids.sys-con.com/proposal infrastructure is essential to competi- Bill Gates didn’t really need to launch
tiveness, particularly at the regional and the broadside he did in his speech at
Subscriptions industry level, it’s no longer a source Microsoft’s CEO Summit on May 21 last
For subscriptions and requests for bulk orders, please send of advantage at the company level. In year:
your letters to Subscription Department subscribe@sys-con.
com. Cover Price: $5.99/issue. Domestic: $69.99/yr. (12 Issues) other words, it doesn’t enable individual
Canada/Mexico: $99.99/yr. Overseas: $99.99/yr. (U.S. Banks or
Money Orders) Back Issues: $10/ea. International $15/ea.
companies to distinguish themselves in And so when somebody says, to take
a meaningful way from their competi- the extreme quote from the Harvard
tors. While essential to competitiveness, Business Review article, they say IT
Editorial Offices
SYS-CON Media, 135 Chestnut Ridge Rd., Montvale, NJ 07645 argued Carr, IT has become inconse- doesn’t matter, they must be saying that
Telephone: 201 802-3000 Fax: 201 782-9638
quential to strategic advantage. IT is with all this information flow, we’ve
Java Developer’s Journal (ISSN#1087-6944) is published monthly
(12 times a year) for $69.99 by SYS-CON Publications, Inc., 135
best viewed (and managed) nowadays, either achieved a limit where it’s just
Chestnut Ridge Road, Montvale, NJ 07645. Periodicals postage he concluded, as a commodity. perfect, everybody sees exactly what they
rates are paid at Montvale, NJ 07645 and additional mailing
offices. Postmaster: Send address changes to: Java Developer’s Of course he never truly meant that want, or we’ve gotten to a point where
Journal, SYS-CON Publications, Inc., 135 Chestnut Ridge Road, IT “didn’t matter”; he merely wanted the it simply can’t be improved – and that’s
Montvale, NJ 07645.
business community to understand that where we’d object very strenuously.
it could no longer rely on it as a source
©Copyright of competitive advantage. Because that wasn’t ever Carr’s
Copyright © 2004 by SYS-CON Publications, Inc. All rights reserved. No
part of this publication may be reproduced or transmitted in Now that the JavaOne techfest has point. What his HBR article was argu-
any form or by any means, electronic or mechanical, including
photocopy or any information storage and retrieval system, without come and gone, but with the Linux- ing was that we’re at the stage in the
written permission. For promotional reprints, contact reprint World Expo still to come, everyone and business/technology cycle where any
coordinator Kristin Kuhnle, kristin@sys-con.com. SYS-CON Media and
SYS-CON Publications, Inc., reserve the right to revise, republish and his dog is naturally busy commenting, technological improvement in the Jeremy Geelan is
authorize its readers to use the articles submitted for publication. interpreting, opining, and dissecting… management of information will be group publisher of
Worldwide Newsstand Distribution so at JDJ we thought it might be useful quickly and broadly copied, rendering SYS-CON Media, and
Curtis Circulation Company, New Milford, NJ
For List Rental Information: to do a round-up of some of what is it meaningless for competitive advan- is responsible for the
Kevin Collopy: 845 731-2684, kevin.collopy@edithroman.com being said about the state of technology, tage. Not that information technology, development of new
Frank Cipolla: 845 731-3832, frank.cipolla@epostdirect.com
the Internet, e-commerce, and all things the Internet, and all kindred phenom- titles and technology
Newsstand Distribution Consultant
Brian J. Gregory/Gregory Associates/W.R.D.S. related. We will publish them in next ena no longer matter. Far less that portals for the
732 607-9941, BJGAssociates@cs.com month’s issue. Already we can reveal improvement is no longer possible. firm. He regularly
Java and Java-based marks are trademarks or registered that one thing emerges above all else: Software developers everywhere – and represents SYS-CON at
trademarks of Sun Microsystems, Inc., in the United States and
other countries. SYS-CON Publications, Inc., is independent of
technology is back – most especially CIOs, CTOs, and CSOs too – certainly conferences and trade
Sun Microsystems, Inc. All brand and product names used on Internet technologies such as search, think it matters, perhaps more than shows, speaking to
these pages are trade names, service marks or trademarks of
their respective companies. storage, and security. It is these three ever. Just as Gates does, and Messrs. technology audiences
items together that are putting the “i” McNealy, Ellison, Dell, and Palmisano. both in North America
back into i-technology in a big way. That is why the “i” is so firmly back in and overseas.
How else can you explain why the i-technology. And why, in turn, the “P”
(possible) market value of Google, is back in IPO. jeremy@sys-con.com

www.SYS-CON.com/JDJ August 2004 3


Relational
database

Object-oriented
development

GET THE RIGHT BACK-END


FOR YOUR FRONT-END
If your back-end database isn't a good match are massively scalable and lightning fast. They
for your front-end development, you need a new require little or no database administration. And
database. Caché’s powerful Web application development
Caché, the post-relational database from environment dramatically reduces the time to
InterSystems, combines high-performance SQL build and modify applications.
for faster queries and an advanced object database We are InterSystems, a specialist in data
for rapidly storing and accessing objects. With management technology for over twenty-six
Caché, no mapping is required between object years. We provide 24x7 support to four million
and relational views of data. Every Caché class can users in 88 countries. Caché powers enterprise
be automatically projected as Java classes or EJB applications in healthcare, financial services,
components with bean-managed persistence. Plus, government, and many other sectors. Caché is
every object class is instantly accessible as tables available for Windows, OpenVMS, Linux, and
via ODBC and JDBC. major UNIX platforms – and it is deployed on
That means huge savings in both development systems ranging from two to over 10,000
and processing time. Applications built on Caché simultaneous users.

Try a better database. For free.


Download a free, fully-functional, non-expiring version of Caché or request it on CD at www.InterSystems.com/match6
© 2004 InterSystems Corporation. All rights reserved. InterSystems Caché is a registered trademark of InterSystems Corporation. 7-04
contents
AUGUST 2004 VOLUME:9 ISSUE:8

JDJ Cover Story Features

Java
Design Patterns
for Long Lists 10 by Heman Robinson
Embedding the Java Virtual
Providing fast performance
44 Machine, Once and for All
by Stanley Wang

FROM THE GROUP PUBLISHER CORE AND INTERNALS VIEWPOINT DOI

Putting the ‘i’ Back into A Tail of Two Tigers A GUI Painter Friendly
i-Technology by Calvin Austin Table Component
by Jeremy Geelan
.................................26 The principle of the column container
.................................3 by Gunnar Grim
.................................48
INTERFACES POI
VIEWPOINT

Walking the Tightrope of Dynamic Sorting with Java Unlocking Microsoft


Microsoft-Java Interoperability A reusable implementation Office Documents
by York Davis
by Derek Spratt
.................................6 .................................32 An open source alternative
by Ryan Ackley and Avik Sengupta
.................................52

28
LABS
JAVA ENTERPRISE VIEWPOINT

The Blind Men, the Elephant,


JNI
VERITAS i3 for J2EE
Calling Java from C Reviewed by Rob Halleron
and App Server Migration A framework for easier JNI .................................60
by Ajit Sagar
.................................8 by Michael Havey
.................................36 PRESSROOM

Industry News Using Apache Cactus


JDJ News Desk by Kishore Kumar
VIDEO/AUDIO .................................64
Web Conferencing Using the DESKTOP JAVA VIEWPOINT

Java Media Framework Swing Low, Swing High, @ THE BACKPAGE

Broadcast and receive media streams Sweet Desktop Unified Diversity JDJ (ISSN#1087-6944) is published monthly (12 times a year) for $69.99 by
SYS-CON Publications, Inc., 135 Chestnut Ridge Road, Montvale, NJ 07645.
Periodicals postage rates are paid at Montvale, NJ 07645 and additional
by Yayati Kasralikar and Pramod Jain by Joe Winchester by Ted Goddard
.................................18 .................................42 .................................66 mailing offices. Postmaster: Send address changes to: JDJ, SYS-CON
Publications, Inc., 135 Chestnut Ridge Road, Montvale, NJ 07645.

www.SYS-CON.com/JDJ August 2004 5


Viewpoint

President and CEO:


Fuat Kircaali fuat@sys-con.com
Vice President, Business Development:
Grisha Davida grisha@sys-con.com
Derek Spratt Group Publisher:
Jeremy Geelan jeremy@sys-con.com

Advertising

Walking the Tightrope of Senior Vice President, Sales and Marketing:


Carmen Gonzalez carmen@sys-con.com
Vice President, Sales and Marketing:
Miles Silverman miles@sys-con.com

Microsoft-Java Interoperability Advertising Sales Director:


Robyn Forma robyn@sys-con.com
Director, Sales and Marketing:
Megan Mussa megan@sys-con.com

I
Associate Sales Managers:
f you were one of the 14,000 by the major vendors in the market to- Kristin Kuhnle kristin@sys-con.com
developers walking the aisles of day. By late 2006 or early 2007, Microsoft Beth Jones beth@sys-con.com
the JavaOne Worldwide Develop- is scheduled to release “Indigo”, a Web Dorothy Gil dorothy@sys-con.com

ers Conference in San Francisco in services interoperability framework that


June, you likely picked up the buzz that should further break down the barriers
Editorial
Executive Editor:
surrounded the issues and opportuni- between Microsoft technologies and Nancy Valentine nancy@sys-con.com
ties presented by the recent agreement Java. Associate Editors:
Jamie Matusow jamie@sys-con.com
between Microsoft and Sun, and the set- While SOAP/XML-based Web services Gail Schultz gail@sys-con.com
tling of their outstanding litigation while fit neatly into the “loosely connected” Jennifer Van Winckel jennifer@sys-con.com
pledging to work together to provide SOA systems arena, they aren’t typically Assistant Editor:
Torrey Gaver torrey@sys-con.com
better support and platform interfaces high performance, which is often of
Online Editor:
for each other’s technologies. concern for enterprises today. Indigo Lin Goetz lin@sys-con.com
Customers likely had their say in the will rely on Web services, so how much
matter. It all boils down to the fact that of the problem will really be solved? Production
Java is here to stay at the enterprise There’s a difference between basic Production Consultant:
Jim Morgan jim@sys-con.com
– “rip up and replace” hasn’t gone over interoperability and high-performance
Lead Designer:
very well since the tech sector melt- interoperability. Therefore, develop- Tami Beatty-Lima tami@sys-con.com
down. Yet .NET is making steady inroads ers need to choose the right balance Art Director:
Alex Botero alex@sys-con.com
into the very same organizations that between cost, performance, and future-
Associate Art Directors:
develop, deploy, and run Java applica- proofing their apps. Louis F. Cuffari louis@sys-con.com
tions – client and server apps alike. Some of the Microsoft–Java interop- Richard Silverberg richards@sys-con.com
There are a whole host of good rea- erability options available on the market Assistant Art Director:
Andrea Boden andrea@sys-con.com
sons for mixing and matching platforms. today will not work with Indigo due to
Derek Spratt is the founder A simple example is the development their reliance on a piece of the System. Web Services
of Intrinsyc and currently of a front-end GUI using Visual Studio/ Runtime.Remoting namespace called Vice President, Information Systems:
serves as its president and .NET to create an app with the familiar channels and formatters. The issue is Robert Diamond robert@sys-con.com
Web Designers:
CEO. Mr. Spratt was also look and feel of Microsoft Windows/Of- that the entire channels/formatters Stephen Kilmurray stephen@sys-con.com
a cofounder and CEO of fice that links to a Java enterprise app subsystem will be removed from Indigo. Matthew Pollotta matthew@sys-con.com
Consequent Technologies, in the back office, and which can be Therefore any software written using
a cofounder and EVP of developed quickly with minimal techni- those features will not run under Indigo. Accounting
PCS Wireless, Inc., the VP cal effort. As Microsoft’s server-based If future support for Indigo is important Financial Analyst:
Joan LaRose joan@sys-con.com
and business unit manager technologies and applications grow for your customers, plan accordingly. Accounts Payable:
of Nexus Engineering, and exponentially, more and more Java- The software industry needs choice Betty White betty@sys-con.com
the product development based client-side applications will have and continuous innovation. The foun- Account Receivable:
Shannon Rymza shannon@sys-con.com
manager in Motorola’s to work seamlessly with .NET in the back dations for future advancements in
Wireless Data Division. office as well. Heterogeneous computing computing are based on these concepts.
He also takes a keen environments are here to stay. For this reason the Sun–Microsoft settle- SYS-CON Events
President, SYS-CON Events:
interest in supporting the This isn’t as hard to accomplish as ment is perhaps one of the best pieces of Grisha Davida grisha@sys-con.com
nonprofit sector and has you might initially perceive it to be. The industry news to date in 2004. Never- Conference Manager:
provided financial and goal of any application architect is to theless, the resulting heterogeneous Lin Goetz lin@sys-con.com
advisory support to the BCT have the flexibility to build applications computing environments do present
Social Venture Partners, in way that optimizes performance and their challenges to systems architects Customer Relations
Circulation Service Coordinators:
BC ScienceWorld, and the cost – the platform it’s built on should and developers. There is a growing list Edna Earle Russell edna@sys-con.com
Sierra Legal Defense Fund. be a secondary factor because high-per- of interoperability options available to Linda Lipton linda@sys-con.com
formance third-party interoperability them that can and should be explored JDJ Store Manager:
Brunilda Staropoli bruni@sys-con.com
dspratt@intrinsyc.com solutions are available and well accepted and leveraged.

6 August 2004 www.SYS-CON.com/JDJ


Java Enterprise Viewpoint

The Blind Men, the Elephant,


Ajit Sagar
Contributing Editor and App Server Migration

T
he six blind men* who attempted planning for such initiatives is very to include a planning phase during
to describe the elephant eventu- complex. The complexity is multiplied which several aspects of migration are
ally described it only from their due to the number and profiles of addressed, some of which are:
perspectives – the parts and not stakeholders in the equation. People • Dependencies between applications
the whole. The same malady can be tend to view migration from a narrow in order to bundle and sequence the
found lurking in one of the problems perspective due to the limited visibil- applications to minimize disrup-
that faces many organizations that ity each individual has into the entire tions
have adopted J2EE as their platform of process. There are several stakeholders • Training, especially if the develop-
choice: the migration of these applica- involved in such migration initiatives, ment team is shifting IDEs
tions between J2EE application servers including: • Shared code libraries, which feed
– be it vendors or versions. The number • Developers who think of migration in into the bundling
of migration initiatives that have come terms of the application code changes • Third-party APIs that may have
up in the past few years is substantial. • Administrators who think of migra- incompatibilities with the new ver-
There are several reasons for this: tion in terms of production runtime sion of the app server/Java platform
• Java, as ever, is rapidly evolving. • Product architects who think of • Integration with in-house utilities
• Although the splitting of Java into migration in terms of the impact on
three platforms (J2EE/J2ME/J2SE) design and product features as well IBM provides a Redbook that serves
happened a few years ago, it took a as the product roadmap as a “how-to” guide for such a migra-
while for the app servers to catch up • Development managers who think tion (http://publib-b.boulder.ibm.
and provide the necessary support. of migration in terms of the resourc- com/Redbooks.nsf/RedbookAbstracts/
• The number of mainstream app es available, existing deadlines, etc. sg246910.html). However, the other
server vendors has died down from • Technical support and services who aspects of migration, such as the ones
a few tens to single digit numbers think of migration in terms of the mentioned earlier, cannot be covered
within the short span of a couple of infrastructure and capacity planning in a generic migration guidebook.
years. • Executive management who think of Someone has to define application
• Since the platform on which the core migration in terms the cost, the risk, characteristics, dependencies, etc.,
product is written has moved on, and the impact on the LOB (Lines of and define a viable strategy for the
Ajit Sagar is a there is no choice but to move. Often Business) migration of each application, as well
senior technical architect the support for an existing version is the migration of all the applications in
with Infosys Technologies, cut off. A typical migration requirement a fixed time frame. Then a team needs
Ltd., a global consulting • The drivers for migration are not that is prevalent in the industry today to manage the migration to ensure it’s
and IT services company. merely limited to app server vendors is migration from IBM WAS 3.5 to done in the proposed manner. The
He has been working with and software. Many companies are WAS 5.0. This is not unexpected. IBM dollars spent up front in such an effort
Java since 1997, and has recognizing the need to shift to open has finally caught up with the latest are a fraction of the amount of money
more than 15 years’ source and Linux platforms as a version of the J2EE platform, but they that will go down the drain if these
experience in the IT industry. more viable alternative. So migration took their time doing it. IBM’s support parameters are not accounted for.
During this tenure, he can involve one or many of several for EJB 2.0 came nearly a year after To do this in a planned fashion,
has been a programmer, dimensions – versions, vendors, competing vendors, such as BEA, had the best recourse is to engage a team
lead architect, director of operating systems, hardware, related provided the same. From a technol- that works solely on this planning
engineering, and product third-party vendors, etc. ogy viewpoint, a migration from 3.5 to initiative, across the applications in
manager for companies from 5.x involves code migration, applica- the scope of the migration. Such a
15 to 25,000 people in size. For most organizations already tion redesign, total repackaging for team needs to operate outside all the
using a J2EE application server, the
Ajit has served as JDJ’s J2EE deployment, and migration of the applications and deliver an analysis
editor, was the foundingupgrade to another version is not dif- entire development environment from that addresses the needs of each ap-
editor of XML-Journal, andficult, if planned properly. However, VAJ to WSAD – just to name a few key plication. This is your seventh (seeing)
has been a frequent speaker the complete migration of several factors. Add the integration with MQ “man” who can paint the true picture
at SYS-CON’s Web Services enterprise applications is not trivial. at IBM clients and throw mainframes of the elephant.
Edge series of conferences.Therefore, it’s critical that adequate into the mix, and the prospect of mi-
He has published more planning be done in advance so that grating 20–50 enterprise applications *THE AMERICAN POET JOHN GODFREY SAXE BASED HIS POEM,

the external factors (besides code


than 75 articles. becomes very formidable. “THE BLIND MEN AND THE ELEPHANT” (WWW.WORDFOCUS.COM/

migration) have minimal impact on The best way for companies to WORD-ACT-BLINDMEN.HTML) ON A FABLE THAT WAS TOLD IN INDIA

ajitsagar@sys-con.com the actual upgrade. The strategy and tackle this type of a tech initiative is MANY YEARS AGO.

8 August 2004 www.SYS-CON.com/JDJ


Feature
A solution with complete support

Embedding the
Java Virtual Machine,
Once and for All
by Stanley Wang

TTL is a portable C++ JNI template library that allows you Of course the VM can always be created in one thread when
the native application starts. However, this is a pure waste if
to embed a JVM within another program. An example of this there is no Java client. The JVM should not be created if there
are no requests.
might be found inside a browser that needs to support Java
Issue 3. The function calls to AttachCurrentThread(...) and
plug-ins. First I’ll discuss the traditional way to embed a JVM DetachCurrent Thread() should be paired so the JVM can get
a chance to free the local references. However, it’s too easy to
within a native program, and then talk about the generic not have the DetachCurrentThread() called by the programmer
(because of multiple flow paths) or by exceptions. A better ap-
solution offered by JTL. proach would be to encapsulate the JVM into a class or classes.

T
o apply the solution provided by JTL, you need to know Thin JVM Wrapper
the basics of Java, C++, and JNI. However, to understand It’s natural to wrap the JavaVM* pointer into a member
JTL’s design you should be familiar with modern C++ variable, say jvm. Because only one JVM in each process can
techniques, such as template programming and the be created (until JDK 1.4.2), the obvious class design is to make
Boost library (www.boost.org). jvm static. Listing 2 shows the first attempt.
All the sample code in this article is written for Microsoft Here the method’s signatures are not important so let’s focus
Windows, but it can easily be ported to other platforms. on the class design. The thin wrapper approach is simple and
straightforward; however, it’s not much better than the C-like
The Traditional Way to Embed the JVM code in Listing 1. It only gets rid of the explicit global variable
Although there are lots of resources on how to embed a JVM, jvm (the static member variable is still kind of global though).
most of them are based on Sheng Liang’s classic book, Java Issues 2 and 3, mentioned in the previous section, still need to
Native Interface: Programmer’s Guide and Specification. Figure be addressed.
1 shows the basic procedure.
If the application has other threads that are using the JVM as Singleton JVM
well, the communications among these threads will look like The Singleton design pattern is described in Design Patterns
Figure 2. by Erich Gamma, et al, as “Ensure a class only has one instance,
Listing 1 shows the typical code (all the error checking and and provide a global point of access of it.” In other words, a
exception handling code in this article has been omitted for Singleton class is a class for which no more than one instance
Stanley Wang is a clarity). This code works fine as long as your program is simple can exist at runtime. This is what the JVM behaves like. We can
lead software developer enough; however, there are three major drawbacks. apply the Singleton pattern to the JVM class design.
at Vcom3D, Inc., and Andrei Alexandrescu has provided all kinds of singleton
the author of JTL. He Issue 1: The JVM is a global variable, which is not acceptable implementations in his book Modern C++ Design and the Loki
received his MS in in some cases. library. Loki has a singleton manager class template, Singleton-
computer science from Holder, that looks like Listing 3.
the University of Florida. Issue 2: The threads in which jvm and env are used and the The template parameter T in Listing 3 is the target class, in
He is interested in thread that launches jvm couple tightly. For example, there our case CJavaVM. Other template parameters specify the poli-
system programming, will be a potential timing issue that’s clearly shown in Figure 2. cies that manage the singleton. As explained in Alexandrescu’s
generic programming, The AttachCurrentThread(...) must be called after the launcher book, “A policy defines a class interface or a class template inter-
database systems, thread initialized jvm, and DetachCurrentThread() must be face. The interface consists of one or all of the following: inner
and computer graphics. called before jvm has been destroyed; otherwise this creates type definitions, member functions, and member variables.”
unnecessary communications overhead between threads. It gets Policy classes are not intended for stand-alone use and their
stanleyycwang@yahoo.com worse when you don’t know which thread is the launcher thread. member functions are often static. In Loki::SingletonHolder, the

10 August 2004 www.SYS-CON.com/JDJ


We have
a problem.

J2EE application problems can grind your business to a


screeching halt, devouring resources and devastating your
quality of service.

Why hunt and peck, trying to recreate the problem and


arguing about who’s to blame?

AppSight breaks through the wall between the place


problems are found and the place they’re solved, so your
team can pinpoint root causes faster than ever.

We’re talking user blunders, configuration problems,


performance issues, all the way down to code errors —

All without taking your application offline.

With AppSight,
it’s problem solved.
Feature

CreationPolicy determines how the singleton instance is created platforms the thread implementation and API are different. To
and destroyed, and the ThreadingModel policy determines make the JVM class design platform portable, it needs to use a
whether the singleton is living in a multiple threaded world. portable threading framework. JTL uses boost::thread because
Listing 4 provides the redesigned CJavaVM class and its usage it’s simple and easy to use, and it will likely be part of the next
with Loki::SingletonHolder. A difference between CJavaVM and version of the standard C++ library.
CJavaVM2 is that all members in CJavaVM2 are not static. Listing Though Alexandrescu provides us with the excellent
4 looks fancier than Listing 1. However, it does not solve the real SingletonHolder class, JTL does not use it directly for two
problems. Issues 2 and 3 are still unresolved. For example, if there main reasons: not all compilers support Loki well and Loki::
are any other threads trying to make a JNI call, it’s still a require- ThreadingModel is only implemented to work with Windows.
ment that the JVM launcher thread has already called jvm.Start- jtl::SingletonHolder does some extension to Loki::Singleton-
JavaVM(). This is because CJavaVM2’s constructor does nothing. Holder to achieve the platform-portable goal. However, jtl::
If StartJavaVM() can be moved into CJavaVM2’s constructor and SingletonHolder uses the same template parameters (and in
DestroyJavaVM() can be moved into CJavaVM2’s destructor, then the same order) as Loki::SingletonHolder, therefore the user
the timing issue will be solved, which is not easy to do. can easily switch to Loki’s version if someday Loki provides us
The major difficulty is that Loki::SingletonHolder’s template with a platform-portable ThreadingModel.
parameter CreationPolicy only calls the target class T’s default Another thing needs to be mentioned for Threading-
constructor. In other words, CJavaVM2’s constructor can- Model – it should be able to work with both the single-thread
not look something like this: CJavaVM2(std::string jvmpath, model and multiple-thread model. If there’s only one thread,
JavaVMInitArgs& args). It must be CJavaVM2(). Period. there’s no sense in doing the synchronization. To achieve this
We are not out of bullets though. The “Every problem can generic solution, JTL provides two class templates, Multiple-
be solved by adding another layer of indirection” idiom applies ThreadModel and SingleThreadModel, as shown in Listing 7.
here. These two classes simply provide type definitions. In
Mul-tipleThreadModel, JTL uses the boost::mutex and
Policy-Based JVM Class boost::mutex::scoped_lock as the synchronization primi-
The solution is to make CJavaVM2 policy-based too. Listing tives, while in SingleThreadModel it uses boostex::faked_
5 shows the new version. mutex and boostex::faked_mutex::scoped_lock as the syn-
In CJavaVM3, a new policy class JavaVMLauncher is intro- chronization primitives. The faked mutex and scoped_lock
duced and declared as follows: are simple extensions to boost mutex and scoped_lock.
They’re empty classes and provide only the required inter-
class JavaVMLauncher { face methods, which are implemented as noop. This is a
public: common trick in generic programming. (ATL programmers
static void LaunchJavaVM(void** ppLib, JavaVM** ppJavaVM); will recall the CComFakeCriticalSection used in CCom-
static void DestroyJavaVM(void* pLib, JavaVM* pJavaVM); SingleThreadModel and CComMultiThreadModel that
} does the same trick.)

ppLib is a pointer to a handle returned by LoadLibrary on JNIEnv Smart Pointers


Windows or dlopen on Solaris. To make JavaVMLauncher more In Listing 6, we solved issues 1 and 2; we no longer have a
generic, the void pointer is used here. The pointer to pointer global variable, and we don’t have a timing issue when calling
method is used for ppLib and ppJavaVM in LaunchJavaVM() AttachCurrentThread() and DetachCurrentThread(). However,
because JavaVMLauncher does not contain any member vari- issue 3 – how to ensure that DetachCurrentThread() is called
ables. It’s the caller to provide the placeholders for the objects – is still unresolved.
pointed to by ppLib and ppJavaVM. DestroyJavaVM() simply When doing JNI programming, most of the time we’re deal-
accepts the cached JavaVM* and lib handle to destroy the JVM ing with the JNIEnv* pointer rather than the JavaVM* pointer.
and free the library. The most important characteristic of the JNIEnv pointer
Now we can invoke the JVM as in Listing 6, which is pretty is that it has thread affinity (it’s only valid in its associated
much what JTL does. In JTL, there is another class template thread). It would be nice if we could get the JNIEnv pointer
called JavaVMMgr that is the placeholder for the JavaVM* and in an arbitrary context. To achieve this and solve issue 3, JTL
pLib. All the JVM calls will be delegated to the JavaVMMgr. provides three smart pointers: simple_env_ ptr, auto_env_ptr,
and thread_env_ptr. They’re all class templates.
Exception Handling Before talking about these smart pointers, let’s review the
The LaunchJavaVM() method in JavaVMLauncher can fail; scenarios in which the JNIEnv pointer is used:
for example, if the user does not have a JRE installed on his 1. In the launcher thread: In this case the ThreadingModel
machine. When this happens, LaunchJavaVM() can return template parameter should be SingleThreadModel to avoid
a flag or error code. In JTL, it will simply throw a jtl::load_ja- unnecessary thread synchronization, even though there
vavm_error exception. may be multiple threads.
2. In multiple threads: AttachCurrentThread() and Detach-
Multithreading, Extending Loki, and boost::thread CurrentThread() will be called only once for each thread.
Remember in Listing 3, Loki::SingletonHolder has a 3. In multiple threads: AttachCurrentThread() and Detach-
template parameter ThreadingModel that’s used to synchro- CurrentThread() can be called multiple times for each
nize the calls to MakeInstance(). However, under different thread (see below).

12 August 2004 www.SYS-CON.com/JDJ


Feature

simple_env_ptr, auto_env_ptr and thread_env_ptr are cor- tor do the job of attaching and detaching the current thread.
responding solutions for scenarios 1, 2, and 3. All these smart Thus we have solved issue 3 and we don’t need to worry about
pointers are derived from env_ ptr_base, which is a place- the missing detaching call. However, auto_env_ ptr may not
holder for JNIEnv* pointer and has other helper functions, work if there is more than one auto_env_ptr instance in the
such as operator->(), operator!(). By the way, all three JNIEnv same thread. This is clear in the following snippet:
smart pointers are not full-blown. For more details about
smart pointers, please refer to Alexandrescu’s book. // auto_env_ptr ptr1, ptr2
The simple_env_ptr is defined as the following: ptr1;
// ...other stuff
template < ... > {
class simple_env_ptr : public env_ptr_base { ptr2;
public: }
//... typedefs for SingletonJVM; // ... from here all calls on ptr1 may be invalid
public:
simple_env_ptr() { In this snippet, when ptr2 is out of scope, its destructor will
SingletonJVM::Instance().GetEnv(&env_, jvm_version); be called, causing the current thread to detach from the JVM.
} This may cause problems because ptr1 is still active; however,
~simple_env_ptr() { env_ = 0;} all its local references may have been freed by the JVM because
}; of the ptr2’s detaching call.
To solve this problem, JTL provides thread_env_ptr, which
In simple_env_ptr’s constructor, the JNIEnv pointer has is defined in Listing 8. thread_env_ptr has a counter that’s
been initialized by calling GetEnv(). This works because the a thread local storage variable. Whenever there is a new
smart pointer is in the launcher thread. thread_env _ptr instance, the counter will be bumped by one.
Similarly, auto_env_ptr is defined as the following: Whenever there is a thread_env_ptr out of scope, the counter
will be decreased by one. When the counter is decreased to
template < ... > zero, the current thread will be detached from the JVM.
class auto_env_ptr : public env_ptr_base {
public: Putting It All Together
//... typedefs for SingletonJVM; Listing 9 illustrates how to use the JTL JVM invocation. You
public: may provide your own JVMLauncher if the default one does
auto_env_ptr() { not meet your requirement.
SingletonJVM::Instance().AttachCurrentThread(&env_, 0);
} Conclusion
~auto_env_ptr() { JTL provides complete support for the JVM invocation. It
if(env_) { also provides JNIEnv smart pointers to get the JNIEnv* pointer
env_ = 0; in arbitrary context. Most of the classes in JTL are designed as
SingletonJVM::Instance().DetachCurrentThread(); class templates and they can easily be extended. JTL provides
} many template parameter implementations as well, which
} can be used as the default template parameter value under
}; // auto_env_ptr most circumstances.
All comments about JTL and this article are highly
As you have seen, auto_env_ptr’s constructor and destruc- appreciated.

Listing 1: The traditional way to launch a JVM void thread_fun() {


typedef jint (JNICALL *pfnCreateJVM)(JavaVM** ppJvm, void** JNIEnv* env = 0;
ppEnv, void* args); // get env
// global jvm, may be used by other threads jvm->AttachCurrentThread(&env, JNI_VERSION_1_2);
JavaVM* jvm; ... ... // work with env
... ... // other stuff jvm->DetachCurrentThread();
// Java VM launcher thread, maybe main thread, maybe not }
JavaVMInitArgs vm_args;
JavaVMOption options[n];
... ... // fill in options Listing 2: Thin JVM wrapper
... ... // fill in vm_args class CJavaVM { // JavaVM* wrapper
// get JNI_CreateVM address private:
HMODULE hModule = ::LoadLibrary(your_libpath); static JavaVM* jvm;
pfnCreateJVM pfn = (pfnCreateJVM)::GetProcAddress(hModule, public:
“JNI_CreateJavaVM”); static bool StartJavaVM(std::string jvmpath,
JNIEnv* env; JavaVMInitArgs& args);
// launch jvm
static bool DestroyJavaVM();
pfn(&jvm, (void**)&env, &vm_args);
static bool GetEnv(JNIEnv** ppEnv, jint version);
// work with env
static bool AttachCurrentThread(JNIEnv** ppEnv, void*
... ...
args);
// destroy jvm
jvm->DestroyJavaVM (); static bool DetachCurrentThread();
jvm = 0; static bool AttachCurrentThreadAsDaemon(JNIEnv** ppEnv,
::FreeLibrary(hModule); void* args);
... ... // other methods
// Java VM consumer thread: thread-1 };

14 August 2004 www.SYS-CON.com/JDJ


Feature

Listing 3: Loki::SingletonHolder class template Listing 7: JTL Threading model


template < template <class Host>
typename T, class SingleThreadModel {
template <class> class CreationPolicy = public:
CreateUsingNew, typedef Host volatile_type;
template <class> class LifetimePolicy =
DefaultLifetime, typedef boostex::faked_mutex mutex;
template <class> class ThreadingModel = typedef boostex::faked_mutex::scoped_lock scoped_lock;
SingleThreaded };
>
class SingletonHolder { template <class Host>
public: class MultipleThreadModel {
static T& Instance(); public:
private: typedef volatile Host volatile_type;
static void MakeInstance();
static void DestroySingleton(); typedef boost::mutex mutex;
typedef boost::mutex::scoped_lock scoped_lock;
typedef typename ThreadingModel<T*>::VolatileType };
PtrInstanceType;
static PtrInstanceType pInstance_;
static bool destroyed_;
Listing 8: thread_env_ptr
}; template < ... >
class thread_env_ptr : public env_ptr_base {
public:
Listing 4: CJavaVM2 with Loki::SingletonHolder //... typedefs for SingletonJVM;
// CJavaVM2.hpp public:
class CJavaVM2 { // JavaVM* wrapper thread_env_ptr() {
private: bool bOk = SingletonJVM::Instance().
JavaVM* jvm; AttachCurrentThread(&env_, 0);
friend Loki::CreateUsingNew<CJavaVM2>; if(bOk) {
CJavaVM2(); if(0 == s_counterptr.get()) {
public: s_counterptr.reset(new int(1));
bool StartJavaVM(std::string jvmpath, JavaVMInitArgs& }else {
args); ++(*s_counterptr);
bool DestroyJavaVM(); }
bool GetEnv(JNIEnv** ppEnv, jint version); }
bool AttachCurrentThread(JNIEnv** ppEnv, void* args); }
bool DetachCurrentThread();
~thread_env_ptr() {
bool AttachCurrentThreadAsDaemon(JNIEnv** ppEnv, void*
if(env_) {
args);
env_ = 0;
... ... // other methods
--(*s_counterptr);
};
if(0 == *s_counterptr) {
// main.cpp SingletonJVM::Instance().
typedef Loki::SingletonHolder<CJavaVM2> JVM; DetachCurrentThread();
int main(){ }
JavaVMInitArgs args; }
std::string libpath; }
JNIEnv* env; private:
...... // fill in libpath and args static boost::thread_specific_ptr<int> s_counterptr;
CJavaVM2& jvm = JVM::Instance(); };
jvm.StartJavaVM(libpath, args);
jvm.GetEnv(&env, JNI_VERSION_1_2); Listing 9: A complete JTL JVM invocation example
...... // working with env // all necessary headers
jvm.DestroyJavaVM(); typedef jtl::win::DefaultJavaVMLauncher JVMLauncher;
} boost::mutex io_mutex; // synchronize std out

Listing 5: CJavaVM3 class Dummy {


template <class JavaVMLauncher> public:
jtl::thread_env_ptr<JVMLauncher> env_;
class CJavaVM3 { void Test() {
private: boostex::ThreadID::ThreadIdType tid = boost-
JavaVM* jvm; ex::ThreadID::get_current_threadid();
boost::mutex::scoped_lock lock(io_mutex);
CJavaVM3 () { JavaVMLauncher::LaunchJavaVM(... /* to do if(env_)
*/); } std::cout << “get JNIEnv* in thread:”
~ CJavaVM3 () { JavaVMLauncher::DestroyJavaVM(... /* to << tid << std::endl;
do */); } else
std::cout << “can not get JNIEnv* in thread:”
public: << tid << std::endl;
bool AttachCurrentThread(JNIEnv** ppEnv, void* args); }
bool GetEnv(JNIEnv** ppEnv, jint version); };
bool AttachCurrentThread(JNIEnv** ppEnv, void* args);
bool DetachCurrentThread(); void launch() // thread function
bool AttachCurrentThreadAsDaemon(JNIEnv** ppEnv, void* {
args); Dummy dummy[3];
... ... // other methods for(int i = 0; i < 3; ++i)
}; {
dummy[i].Test();
Listing 6: JVM invocation with CJavaVM3 }
// main.cpp }
typedef CJavaVM3<YourLauncher> CJavaVM; int main()
typedef Loki::SingletonHolder<CJavaVM> JVM; {
boost::thread thrd(&launch);
int main(){
JNIEnv* env; Dummy dummy;
dummy.Test();
CJavaVM2& jvm = JVM::Instance();
jvm.GetEnv(&env, JNI_VERSION_1_2); thrd.join();
...... // working with env
return 0;
} }

16 August 2004 www.SYS-CON.com/JDJ


������������������
��������������������
������ ���� ������� ���� ������ ��� ����������� �������� ���
�������� ��� ������������� ������������ ���� ������������
��������� ��� ���������� ������� ���� ������� ���������� ����� ���
����� ��� ����������� ���� ������� ������������� ���� ��� ���
��������������������������������������������

��������������������������������� ��������
������������� ������������������������
�����������������������������������������������
����� ������ ��� ��� ����� ����������� ������� �������
�������������������������������������������������
�����
����������
������� ���� ��� ��������� ���� ������ ��� ���������� ����������
����
�� �� ��
����
�������� ���
����������� ������� ����� ����� ����� ���� ���� ���� ��������
�� �� ��
���� �� ��
��������
�� ���� �������� �� ���� � ����
����� ����� ������ �������� ������������� ��������� ��
��� ����
��� ���
������
�������� ������ �
�� �� ��� ���� ����
��������������������������������������������� ����� ��
��
�������
��� �� ��

� �� �������� �� �� � �� ������
�� ��
��������������������� ��� ���� � ��
������ ����� ��
������ �� ������
��
���� ����
�� ��
���� ����������
������
����������������������������������������������������� �������� ��������
�������� ����� ��
�� �� �� � ���� ��
������ �����
��������������������������������������������������� ��������
��������
��������
��� �������������� �������� ������������ �������� ����
��������� ��������� ������������ ��������� ���� ����� ����������������������
��������������������������������
���������������������������������������������

����������������������������������������������������
������������������������������������������������������
�������������������������������������������������������
���� �� ����� ������� ������ ���� ��������������� �����������
����������������������������������������������

�����������������������������������������������������

�������������������������

�������������������������
��������������
����������������������������

������������������������������������

�������������������������������������������������������������������������������������������
���������������������������������������������������������������
Video/Audio

Web Conferencing Using the


Java Media Framework by Yayati Kasralikar and
Pramod Jain

Broadcast and receive media streams

T
his article describes our ex- Users don’t have to wait for the whole Here, MediaLocator is a class that
periences with developing a media file to be downloaded before JMF uses to represent audio or video
browser-based Web conferencing watching. To enable real-time stream- media location and is created as follows:
application with the following ing, dedicated streaming media servers
constraints: and streaming protocols, such as Real- MediaLocator mediaLocator = new
1. HTTP protocol (port 80) to broad- Time Protocol (RTP), are required. RTP MediaLocator("vfw://0");
cast and receive video/audio is an Internet standard for transporting
2. Broadcasters and receivers are not real-time data. It uses the unreliable 2. The Player class is used to play
required to have public IP addresses UDP protocol to transmit packets. media files or stream media. A play-
3. Multiple users, each capable of A variant of real-time streaming is er is constructed from MediaLocator
broadcasting to and receiving feeds progressive streaming, also called HTTP or the media URL as follows:
from many users streaming because it uses the commonly
4. Low-cost solution for continuous used HTTP protocol and standard HTTP Player player = Manager.createPlayer(media
video/audio feed servers to deliver media files. Progressive Locator);
streaming enables files to be watched as
Java Media Framework (JMF) is used they are downloaded. When the client Once the player is realized (ready to
to develop the browser-based Web con- makes a request (HTTP) to the server play state), you can call player.start()
ferencing application. In this architecture, for the media file, the file eventually gets to play the media. A realized player
the client uses two JMF applets – one for stored in the client’s memory buffer. The can be created from the DataSource:
capturing video/audio from a Webcam playback is allowed before the entire file
and the other for playing video/audio gets downloaded. Most firewalls allow Player player = Manager.createRealizedPla
Pramod Jain is president, feed. The capture applet continuously traffic over HTTP whereas RTP is not yer(ds);
Innovative Decision captures video/audio feed for a specified permitted by most firewalls. In our ap-
Technologies, Inc. (INDENT). length of time (e.g., 10 seconds) and saves proach, we’re emulating HTTP streaming. 3. A processor is a type of player. Besides
INDENT has built several it locally in a file. This file is uploaded playing the media, it can also out-
large-scale Java-based to a Web server using an upload servlet. Introduction to Java Media Framework put media through a DataSource to
collaboration portals. The media stream is stored in MSVIDEO The JMF API specifies a simple, uni- another player or processor. A proces-
Pramod has a PhD from (AVI) or QUICKTIME (MOV) format. The fied architecture to synchronize and sor is used to manipulate the data
the University of player applet then continuously fetches control audio, video, and other time- and convert the data from one for-
California, Berkeley. the media clips from the Web server. The based data within Java applications and mat to another. It’s created from the
player applet uses perfecting capability to applets. JMF software, documentation, DataSource, MediaLocator, or a URL:
pramod@indent.org play clips from the server in a continuous sample programs, and the source code
manner. The advantages of this approach can be downloaded from Sun’s Web site Processor processor = Manager.
are that it does not require expensive at http://java.sun.com/products/java- createProcessor(new URL(“http://localhost/
streaming servers, and it satisfies the media/jmf. In this section, we’ll briefly test.mov));
constraints mentioned earlier. discuss the basic concepts of JMF, in-
The article will start with a brief cluding a few useful classes required to 4. A manager is one of the most impor-
explanation about real-time streaming, build a Web conferencing application: tant classes of JMF. It handles the
followed by an introduction to JMF, a 1. The DataSource class is an abstrac- construction of players, processors,
Yayati Kasralikar is lead description of the capture and player tion that represents audio, video, and DataSources, as we have seen
programmer at Innovative applets, and a comparison with other or a combination of both. A data earlier.
Decision Technologies, Inc. technologies. source can be a file or a stream and
(INDENT). He holds an is constructed from the Manager Architecture Description
MS from the University of Introduction to Real-Time and MediaLocator as follows: The architecture of our approach
Central Florida, Orlando. and Progressive Streaming is shown in Figure 1. It implements
Real-time streaming of media allows DataSource ds = javax.media.Manager.createD a Web conferencing application
yayati@indent.org users to play media as they receive it. ataSource(mediaLocator); over HTTP. The architecture has one

18 August 2004 www.SYS-CON.com/JDJ


A free offer for readers of Java Developer’s Journal!
Formula One e.Spreadsheet Engine:
Finally, there’s a supported, Pure Java
tool that merges the power of Excel
spreadsheets and Java applications. Download
1 Automatically generate dynamic this quick-read
Excel reports. No more manual white paper
querying and cutting-and-pasting and trial today!
to create Excel reports!
2 Manage calculations and business
rules on J2EE servers with Excel
files. No more translating Excel
formulas to Java code! Download your trial and test our demos
3 Embed live, Excel-compatible data and sample code. See for yourself how
grids in applets and Java desktop the Formula One e.Spreadsheet Engine
applications. No more static HTML can help your Java application leverage
or presentation-only data grids! the skills of Excel users in your business.

http://www.reportingengines.com/download/21ways.jsp

LS,
TRIA
FREEMOS, &
DE PLE
SAM E!
COD

888-884-8665 • www.reportingengines.com
sales@reportingengines.com

Build reports against JDBC, XML, Java objects, BEA Portal Server logs, BEA
Liquid Data, and other sources visually or with Java code. It’s embedded!
No external report server to set up. Unlimited users and CPUs per license.
http://www.reportingengines.com/download/f1ere.jsp
Copyright © 2004 ReportingEngines (a division of Actuate Corporation). All rights reserved. Formula One is a registered trademark of Actuate Corporation.
Java and Java-based trademarks and logos are the trademarks or registered trademarks of Sun Microsystems Inc., in the United States and other countries. All other trademarks are property of their respective owners. All specifications subject to change without notice.
Video/Audio

centralized server and one or many Suppose: size should be less than 20Kbits. If the
distributed clients. The server has a clip size is 10 seconds, the maximum
Web server and a servlet container. One second file clip size = oneSecFileSize bits playback lag will be 30 seconds. We have
Clients run two applets, one for cap- Time duration of each clip = cSec seconds observed that the minimum file size for
turing media and the other for playing Upload Transmission rate = uRate bits per transmitting a one-second video (with
the media. second no audio) is 8Kbits using H263 encoding
The high level steps are: Download Transmission rate = dRate bits per and 128x96 pixels video size. H263 en-
1. The applet continuously captures second coding is ideal for a low-bandwidth en-
video and audio streams from Time to upload, tUpload = oneSecFileSize vironment because it produces smaller
the Webcam. These streams are *cSec/uRate file sizes. The H263 encoder in the JMF
saved locally in a specified format Time to download, tDownload = oneSecFileSize 2.0 is capable of handling only limited
as a file every few seconds. This *cSec/dRate video sizes (only 352x288, 176x144, and
file is uploaded to the server over 128x96). We observed a minimum file
HTTP using a file upload servlet. If the time to upload or download a clip size with the video and an 8-bit mono
Uploading uses a separate thread. is more than the time to play a clip, the audio with an 8000Hz sampling rate to
A significant loss of frames will player will wait and the receiver will see a be 80Kbits.
result if the file upload is in the break, i.e., max(tUpload,tDownload)>c
same thread as file capture. Note Sec. For the continuous playing of clips, • Either the sender or receiver has a
that a more efficient method the following condition must be true: low bandwidth connection
would be to write these streams Let’s assume that the lower rate is rate
directly on the server using a Max (1/uRate, 1/dRate) > 1/ oneSecFileSize = 20Kbits/sec and the other rate is much
socket. This is currently not pos- Min (uRate, dRate) > oneSecFileSize higher. In this case the one-second file
sible because the DataSource size should be less than 20Kbits, but
class provided with JMF does According to the equation, the wait the maximum playback lag is about 20
not contain a method to get time between clips at the receiver does seconds if the clip size is 10 seconds.
the InputStream. A custom not depend on clip size. The only vari-
InputStream-based DataSource able that matters for a continuous play- • Both sender and receiver have high
can be developed (e.g., http:// back is the size of a one-second file and bandwidth
www.extollit.com/isdsjmf.php). that the provided upload and download In this case better quality video can be
2. A server gets a new file clip from rates meet the above condition. Lag transmitted. The playback lag will be the
the sender and stores it in a sender- time between playing and capturing is: same as the clip size in seconds. JPEG
specific directory. A counter, such encoding offers good quality video and is
as filename+i, is attached to the file- cSec + tupload + tdownload well suited to a high-bandwidth environ-
name. ment. File sizes can be decreased during
3. The JMF Player applet continuously From the above equation, the maxi- JPEG encoding by lowering JPEG quality.
downloads new files from the Web mum lag with no break in the feed is
server. It uses JMF’s perfecting capa- 3*cSec, and the minimum lag is cSec. There are no easy guidelines to
bility to play these clips in a con- To get a Web conference that is as predict the exact size of the one-second
tinuous manner. When the current close to real time as possible, cSec clip; it depends on the video size, the
clip is being played, a new instance should be reduced. Next, we will apply audio sampling rate, video and audio
of Player is created for the next clip the above analysis to the following cases. encoding, the frame rate, and the file
and the next clip is downloaded format. Users should experiment with
from the server. This makes the play- • Both sender and receiver have a low using different values for these param-
ing of clips continuous, as the next bandwidth modem connection eters and a variety of movement in the
clip to be played has already been Let’s assume the uRate = dRate = 20K video to determine an approximate one-
prefetched. Note that the entire clip bits/sec. In this case, the one-second file second file size.
is downloaded by the player applet
before playing it.
WebCam File Upload Servlet
At the start of playing and during
the process of fetching a new clip, the vfw/directSound
player applet checks new file availabil- JMF Player
Applet
ity for n seconds before timing out.
P
HTT

JMF Capture Applet


TP
HT
Computation of Parameters
First, we’ll do an approximate
Directory of File Clips Receiver
mathematical analysis for bandwidth Upload Thread
consideration and demonstrate the
Sender Server
usability of our approach with a few
special cases. Figure 1 Architecture

20 August 2004 www.SYS-CON.com/JDJ


Video/Audio

JMF Capture Applet JMF Player Applet 2. Extending the DataSource class to
The high-level steps for developing The high-level steps for developing allow InputStream-based process-
capture applet are (see Listing 1): a player applet are (see Listing 3): ing to save the media directly at the
1. A DataSource is created from 1. Construct two players from the URL server and remove the need
the Webcam source using the of the media at the Web server. One for a local buffer.
MediaLocator. player is for the current clip and the 3. To package and deliver required
2. A ProcessorModel is created from other is for the next clip. dlls and registry files of JMF so
the DataSource, the format object 2. Start the first player and fetch the that there’s no need to install JMF
specifying the video format, and the next clip using the second player. software.
FileDescriptor object specifying the 3. On the EndOfMediaEvent for clip
output file format. i, start playing clip i+1. Destroy the Comparison to JMF-Based P2P
3. A Processor is created from the visual component for the player Web Conferencing Using RTP
ProcessorModel and the output of clip i, de-allocate the player, Thus far, we have described an
DataSource is obtained from the and create a new player for clip HTTP-based approach that involves
Processor. i+2. Prefetch the clip i+2 and add no real-time streaming. An alterna-
4. A DataSink object is created by first ControllerListener. Repeat these tive to the above approach is a peer-
creating a MediaLocator for storing steps for subsequent clips. to-peer, RTP-based Web conferencing
the media in a file. solution that can be developed
5. Capture of the stream is started and This makes the playing of clips using the JMF API. The source code
the stream is saved for a specified continuous, as there will be little or for the RTP Server/Sender can be
duration into a file. minimal delay between subsequent found at http://java.sun.com/
clips. Note that the entire clip is down- products/java-media/jmf/2.1.1/
This process is repeated until the loaded by the player applet before solutions/AVTransmit.html and at
sender ends the session. playing it. http://java.sun.com/products/java-
media/jmf/2.1.1/samples/sample-
File Upload HTML Code for Sender and Receiver Applets code.html#RTPPlayerApplet for
The File Upload uses the JUpload The HTML code for the sender ap- the RTP Player applet. The RTP Ser-
project (http://jupload.sourceforge. plet is shown in Listing 4. ver cap-tures the media from the
net/). It has two parts: the file upload The HTML code for the receiver ap- Webcam and streams it to receivers
thread at the client and the upload plet is shown in Listing 5. Note that this by specifying IP addresses and
servlet at the server. The following HTML page is generated dynamically port numbers. The RTP Player
are the steps for developing the File with the appropriate senderID and listens on a specific port for
Upload thread (see Listing 2): current counter. If the receiver wants to streams coming form the sender’s
1. Create a socket connection with the receive multiple feeds, multiple applet IP address.
server. entries are generated in HTML. The primary difference between
2. Create an HTTP POST request and the HTTP approach and the RTP ap-
an HTTP head and tail. Drawbacks proach is that RTP streams the feeds
3. Create necessary IO stream objects. 1. There is a lag between capturing and continuously to receivers without
4. Send an HTTP request to the server. playing. storing them in files locally or at the
Write the HTTP head, the clip file, 2. It involves expensive disk write server. The disadvantages of the
and the HTTP tail to the server. operations. above RTP approach are:
3. Both receivers and senders must 1. Public IP addresses are required
The Upload Servlet uses O’Reilly’s have JMF software installed. for both the sender and the
multipart request executor (www. receiver.
servlets.com/cos/index.html) to Future Enhancements 2. The senders and receivers should
upload the files. MultipartRequest 1. A sophisticated in-memory buffer- not be behind firewalls because
is a utility class that handles mul- ing mechanism to allow better video RTP is not allowed by most corpo-
tipart/form-data requests for file quality and efficient delivery by rate firewalls.
uploads. eliminating expensive disk writes 3. Also, as the number of partici-
pants increases, the number of
ports also increases linearly. This
1 User Management 2 makes user and port management
(at start of challenging.
each user session) 4. The default RTP implementation
Sender Receiver of JMF uses the unreliable UDP
protocol, so delivery time and
Streaming Server
3 4
quality are not guaranteed – it may
result in the dropping of frames or
make frames out of sequence dur-
Figure 2 Web conferencing using streaming servers ing transmission.

22 August 2004 www.SYS-CON.com/JDJ


-
Video/Audio

Comparison to Web Conferencing Using ers use the encoder to stream the media Conclusion
Streaming Servers to the server. The server then streams The approach presented here offers a
The architecture of the Web conferenc- the media to receivers. The disadvan- near real-time, low-cost Web conferencing
ing system using commercially streaming tages of this approach are: solution. It allows multiple users to broad-
servers is shown in Figure 2. Senders first 1. The architecture is heavy as it cast and receive media streams, it uses the
register a unique broadcast/mount point involves the use of costly and com- HTTP protocol, and does not require the
with a user management component as plex streaming servers, players, and broadcaster and receiver to have public IP
shown by arrow 1. The sender then uses encoders addresses. The source code for this article
streaming protocol (for example, RTP 2. It’s not an open architecture. The is available at www.indent.org/jdj-jmf/.
or RTSP) to push the media stream to a architecture becomes specific to one
centralized streaming server, as shown by particular system such as RealSystem, References
arrow 3. Receivers first look for senders which makes it nonportable with • Java Media Framework (JMF): http://
at the user management component (as solutions from other vendors. java.sun.com/products/java-media/
shown by arrow 2) and obtain corre- 3. Capture programs, a.k.a. encoders, jmf/
sponding broadcast addresses. Receivers are not readily available and are not • JMF RTP Support: http://java.sun.
then request and receive media from the browser based. com/products/java-media/jmf/ 2.1.1/
streaming server, as shown by arrow 4. 4. It uses special streaming protocols support-rtp.html
In this approach we don’t need to such as RTP or RTSP, which are not • Mack, S. (2002). Streaming Media
break the feed into smaller clips. Send- allowed through a firewall. Bible. Hungry Minds.

Listing 1: JMF Capture Applet Listing 3: JMF Player Applet


Step-1 Step-1
videoDataSource = javax.media.Manager.createDataSource(vide URL mediaURL1 = new URL(videoDir + mediaFile + counter +
oMediaLocator); ".mov");
Step-2 counter++;
videoOutputFormat[0] = new VideoFormat(VideoFormat.H263, new URL mediaURL2 = new URL(videoDir + mediaFile + counter +
Dimension(160,120), Format.NOT_SPECIFIED, null, 15); ".mov");
outputType = new FileTypeDescriptor(FileTypeDescriptor. Player player1 = Manager.createPlayer(mediaURL1);
QUICKTIME); Player player2 = Manager.createPlayer(mediaURL2);
ProcessorModel processorModel = new ProcessorModel(videoDat Step-2
aSource, videoOutputFormat, outputType); player1.start();
Step-3 player2.fetch();
videoProcessor = Manager.createRealizedProcessor(processor Step-3
Model); player2.start();
if (videoProcessor != null) videoDataSource = videoProces- add(player2.getVisualComponent());
sor.getDataOutput(); if(visualComp!=null) remove(visualComp);
Step-4 visualComp = player2.getVisualComponent();
MediaLocator dest = new MediaLocator("file://" + file); counter++;
DataSink filewriter = Manager.createDataSink(videoDataSourc URL mediaURL = new URL(videoDir + mediaFile + counter +
e, dest); ".mov");
filewriter.open(); player = Manager.createRealizedPlayer(mediaURL);
Step-5 player.addControllerListener(this);
filewriter.start(); player.prefetch();
videoProcessor.start();

Listing 4: Sender HTML code


Listing 2: File Upload Thread <html> <head>
Step-1 <body>
URL url = new URL(“http://localhost:80/jmf/parserUpload. <applet code=SaveVideoApplet.class width=320
jsp”); height=280>
Socket sock = new Socket(url.getHost(), (-1 == url.get- <param name=archive value="jmf.jar">
Port()) ? 80 : url.getPort()); <param name=counter value="0">
<param name=uploadurl value="http:/localhost/jmf/
Step-2
upload.jsp">
header.append("POST "); <!-- URL of the Upload Servlet -->
header.append(url.getPath()); <param name=sender value="test">
header.append(" HTTP/1.0\r\n"); <!-- sender id -->
header.append("Content-type: multipart/form-data; bound- </applet>
ary="); </body></html>
header.append(boundary.substring(2, boundary.length()) +
"\r\n");
header.append("Content-length: "); Listing 5: Receiver HTML code
<html> <body>
header.append(contentLength);
<applet code=PlayerApplet.class width=320 height=280>
header.append("\r\n");
<param name=archive value=”jmf.jar”>
header.append("\r\n");
<param name=counter value=”0”> <!-- counter at the
Step-3 time of request -->
dataout = new DataOutputStream(new BufferedOutputStream(soc <param name=sender value=”test”> <!-- sender id -->
k.getOutputStream())); <param name=rate value=”1.0”> <!-- rate at which
datain = new BufferedReader(new InputStreamReader(sock.get- player sees the video -->
InputStream())); <param name=videodir value=”http://localhost/jmf/vid-
Step-4 eos/”> <!-- server directory; all clips from sender will be
dataout.writeBytes(header.toString()); at http://localhost/jmf/videos/ -->
uploadFileStream(files, dataout); </applet>
dataout.writeBytes(tail.toString()); </body></html>

24 August 2004 www.SYS-CON.com/JDJ


Core and Internals Viewpoint

Calvin Austin
Core and Internals Editor

A Tail of Two Tigers


I
recently enjoyed reading A Short ence reminded me of some of the less. My second promise is that
History of Nearly Everything by best. Packed with technical content there will be a special focus on
Bill Bryson. In his book, Bill goes and with nearly 15,000 attendees, J2SE 5.0 throughout the year. Don’t
back to basics and delves into it represented a renewal in the com- worry, there will still be room for
the history of many things we take as munity. A renewal that will result content for older releases too.
facts. One memorable observation is in new tools, new books, and new There has been a fair amount of
a reminder that we are all just collec- products based on the J2SE 5.0 foun- attention centered on the language
tions of trillions of atoms assembled dation. By the time you read this, features, like Generics, Metadata,
in a unique configuration, a one off, the J2SE 5.0 JSRs will be heading and the enhanced for loop, to name
never to be repeated again. into the final stages of the Java Com- a few. The language changes are
Given this cosmological certainly a core part of the re-
randomness I’m at a loss to lease; however, there are many
explain how we ended up other features that are just as
with two very fine articles useful yet not as well known.
about JNI this month. The Features like performance and
random skew doesn’t end monitoring can be used with
there. I recently presented existing applications without
a session at the JavaOne changing a single line of code.
conference about the J2SE 5.0 Some features, like the new
release, code named “Tiger.” profiling API, will require a
At the same time, Apple was fair amount of porting. To help
headlining the OS X.4 release make that transition easier, I
at the WorldWide Developer will be searching for case stud-
Conference, barely a block ies. My aim is to give you the
away, and their release was also code munity Process, the Final Approval tools and techniques to ramp up to
named “Tiger.” Ballot. Although that marks the end using J2SE 5.0. This is also your op-
However, this is where the parallel of the JCP and engineering cycle, it portunity to help out fellow develop-
universe stops. While Apple users also represents the first day of J2SE ers. If you are interested in writing
were bemoaning the lack of access to 5.0 in real deployments and ultimate- some J2SE 5.0 material, please send
key information like bug reports, the ly the success of the platform. your proposal to http://grids.sys-
Java community was treated to a cute You may be thinking, what’s in con.com/proposal.
tiger cub, new open source projects, it for me, the regular JDJ reader? Finally, I would like to thank Joe
Java3D and Project Looking Glass, Well, I will make two promises. Ottinger for steering the JDJ ship for
A co-editor of JDJ since and the arrival of the next update to First, expect the same high-quali- the past year. Joe suggested I use my
June 2004, Calvin Austin the Java platform, now renamed J2SE ty technical articles that you have J2SE 5.0 experience to guide the core
is the J2SE 5.0 Specification 5.0. been used to. I’ve been reading section this year and I hope to make
Lead at Sun Microsystems. I have attended all nine JavaOne and writing for JDJ for many years good on that suggestion. Let us make
He has been with Java conferences and this year’s confer- and wouldn’t settle for anything this a year to remember.
Software since 1996 and


is the Specification Lead
for JSR-176, which defines
the J2SE 5.0 (“Tiger”) By the time you read this, the J2SE 5.0 JSRs will be heading into the
release contents.
final stages of the Java Community Process, the Final Approval Ballot”
calvin.austin@sys-con.com

26 August 2004 www.SYS-CON.com/JDJ


©2004 SLEEPYCAT SOFTWARE INC. ALL RIGHTS RESERVED.

Javavavoom!
Introducing a high-performance database that’s 100% Java.

Berkeley DB Java Edition


Finally there’s a high-performance database that loves Java just as
much as you do: Berkeley DB Java Edition (JE). Brought to you by the
makers of the ubiquitous Berkeley DB, Berkeley DB JE has been written
entirely in Java from the ground up and is tailor-made for today’s
Download at www.sleepycat.com/bdbje
demanding enterprise and service provider applications.

Berkeley DB JE has a unique architecture that’s built for speed. The software executes in the JVM of your application,
with no runtime data translation or mapping required. Plus Berkeley DB JE has been specifically designed to
handle highly concurrent transactions, comfortably managing gigabytes of data. And because it’s built in your
language of choice, your organization enjoys shorter development cycles and accelerated time-to-market.

Experience the outstanding performance of Berkeley DB JE for yourself.


Download Berkeley DB JE today at www.sleepycat.com/bdbje. Register now, and you’ll also receive a 15%
discount on a commercial license purchased before November 30, 2004.
Feature

Testing server-side components

by Kishore Kumar

A
pache Cactus is part of the Jakarta project and is an the redirector proxy). The client-side instance is used to run
the method beginXXX and endXXX and the server-side
open source framework for unit testing server-side instance is used to run the test methods. The redirector also
initializes the TestCase instance with server-side implicit ob-
Java code. It uses and extends the JUnit framework jects (HttpServletRequest, HttpServletResponse, ServletCon-
text,…) which are made available to the test methods.
and facilitates unit testing of servlets, JSPs, Taglibs, EJBs, and filters. 4. The setUp method is executed. If required, implement this
method to define a test fixture.
Testing server-side components is more complicated than 5. The redirector executes the test method (testXXX).
testing client-side code because these components interact 6. The test method usually instantiates the component-under-
with a container and require access to many container-man- test and invokes the methods that need to be tested. It uses
aged objects such as request and session. It’s possible to make JUnit assert API (assertEquals, assert,…) to verify the result.
a mock-up of all the container-managed objects and test the 7. The tearDown method is executed. If required, implement
components. These mock objects provide a “clean” environ- this method to do clean up.
ment for testing that is totally isolated from the container. The 8. If the test fails, the redirector proxy handles the exception
other approach is to use an in-container strategy. Using this, thrown from testXXX.
the test code runs on a real (not mock) container and uses real 9. If an exception has been raised, the proxy returns the
container-managed objects. Both approaches have their advan- exception information back to the client side.
tages and disadvantages. Cactus is based on the in-container 10. If no exception has occurred, the method endXXX(org.
testing and our discussion will focus on this approach. apache.cactus.WebResponse) or endXXX(com.meterware.
I’ll explore how to use the Cactus framework to write JUnit- httpunit.WebResponse)* is executed if it is defined. This
based test classes for testing server-side components. method may be implemented to verify the response
from the server-side component.
Understanding Cactus – How It Works * This signature is used for HttpUnit integration

Cactus tests are organized into Cactus TestCase classes.


You can subclass and implement any of the three provided Cactus Redirectors
Cactus TestCase classes: ServletTestCase, JspTestCase, and Cactus provides three redirectors: ServletRedirector,
FilterTestCase. Figure 1 explains the overall system. JspRedirector, and FilterRedirector. Cactus TestCase uses a
Here, XXX is the name of the test. Unlike a JUnit test, the corresponding redirector implementation (for example, Serv-
Cactus test runs in two different environments: client-side letTestCase uses ServletRedirector). The implicit objects that
and server-side. The class-under-test is a server component are created and initialized in a Cactus test instance depend
like a servlet or a JSP. The following are the different steps that on the specific redirector. A servlet redirector initializes a
occur when a Cactus test (testXXX) is run: servlet test case with servlet API objects. On the other hand, a
1. The JUnit TestRunner executes the TestCase method runTest. If JSP redirector initializes a JSP test case instance with JSP API
defined, the method beginXXX is executed. This method may objects.
be implemented to initialize a Web request (HTTP parameters
and headers) to the server-side component-under-test. Writing a Cactus Test
Kishore Kumar works 2. Cactus opens an HTTP connection to a Cactus redirector To write a Cactus test, complete the following steps:
as a Java architect at proxy. All the parameters set up in step 1 are sent in the 1. Implement a subclass of a Cactus TestCase implementa-
US Technology (www.ustri. HTTP request. tion. Subclass the ServletTestCase class if your component-
com). He specializes 3. The redirector acts like a proxy on the server-side for your tests. under-test is a servlet or subclass the JspTestCase class if
in J2EE applications. It creates a new instance of the TestCase class and executes the your component-under-test uses JSP API objects. If your
test. The TestCase class is instantiated twice: once on the cli- component-under-test is a servlet filter, extend your test from
kishore_kumar@usswi.com ent-side (by the TestRunner) and once on the server-side (by FilterTestCase.

28 August 2004 www.SYS-CON.com/JDJ


public class TestSampleServlet extends ServletTestCase }
{ public void testXXX()
} {
ServletToTest s=new ServletToTest();
2. Implement standard JUnit methods. As in a normal JUnit test, s.init(config);
define the following JUnit methods in your test case class: s.methodToTest();
• A constructor with a single string parameter, which is the assertEquals(“some value”, session.getAttribute(“result”));
test name that needs to be executed when the test is run. }
• A method suite to collect the test into a JUnit TestSuite public void endXXX(WebResponse response)
object. Running the TestSuite will run all contained {
tests. A convenient TestSuite constructor can create Cookie cookie=response.getCookie(“someCookie”);
a suite object that contains test case instances for every assertEquals(“some value”,cookie.getvalue());
method starting with “test” in a given class. }

public TestSampleServlet(String testName) Testing JSPs


{ Testing JSPs covers the following: verifying the result of JSP
super(testName); processing (HTML) and unit testing JSP tag libraries. Unit test-
} ing tag libraries are discussed later.
public static Test suite() You can still have your test case class extend from Serv-
{ letTestCase if your test does not use any of the JSP API objects
return new TestSuite(TestSampleServlet.class); (like PageContext).
} The Web response can be easily verified by implementing
the method endXXX in a ServletTestCase subclass.
• Override the method setUp to initialize a test fixture
and the method tearDown to clean up the fixture. public class SimpleTest extends ServletTestCase
These are executed at the server side and all the server- {
side implicit objects are available to these methods. […]
3. Implement the testXXX method. In the test method, public void testXXX()
you will: {
• Instantiate the component-under-test. Since the test RequestDispatcher rd=config.getServletContext().
case extends Cactus TestCase, server-side implicit getRequestDispatcher(“test.jsp”).
objects are defined and initialized with valid values. rd.forward(request,response);
These are available to the test methods through }
TestCase instance members. }
• Call the method to be tested. public void endXXX(org.apache.cactus.WebResponse webResponse)
• Perform JUnit standard asserts (assertTrue, assert, …) {
to verify the result. // Assert Result
[ … ]
public void testXXX() }
{
SampleServlet servlet=new SampleServlet(); Cactus also integrates HttpUnit into the framework. The
// session is an implicit object defined in cactus TestCase class HttpUnit implementation of the WebResponse object (com.
session.setAttribute(“name”,”value”); meterware.httpunit.WebResponse theResponse) can be used
String result=servlet.doSomething(request); to verify the HTML response.
assertEquals(“some value”,result);
} public void endXXX(com.meterware.httpunit.WebResponse theResponse)
{
4. Implement the method beginXXX to initialize the HTTP WebTable table = theResponse.getTables()[0];
request to the server. assertEquals("rows", 4, table.getRowCount());
5. Implement the method endXXX to verify the HTTP assertEquals("columns", 3, table.getColumnCount());
response from the server. assertEquals("links", 1, table.getTableCell(0, 2).getLinks().
length);
Testing Servlets }
You need to subclass and implement a ServletTestCase
to test a servlet. The ServletTestCase provides the follow- Testing JSP Tag Libraries 4. setUp()
5. testXXX()
ing implicit objects: request (HttpServletRequest), response For testing JSP Tag libraries, 7. tearDown()
1. beginXXX() 3
(HttpServletResponse), session (HttpSession), and config extend your test case class 2
Redirector
(ServletConfig). The ServletTestCase uses the ServletRedirec- from JspTestCase. In addition Cactus Test Case Proxy Cactus Test Case

tor as the proxy to servlet tests. to the servlet implicit objects, 9 8 6


10. endXXX()
JspTestCase provides the Class Under
public void beginXXX(WebRequest request) following implicit objects: out Test
Client-side server-side
{ (JspWriter) and pageContext
request.addParameter(“param1”,”value”); (PageContext). These implicit Figure 1 Cactus System

www.SYS-CON.com/JDJ August 2004 29


Feature

objects are made available to the setUp, tearDown, and textXXX Testing Body Tags
methods as instance variables of the JspTestCase class. For testing tags with body content you must replicate the
To test the tag handler, use the implicit objects provided by life cycle of the tag in your test code. Use the page context
the JspTestCase to set up initial state for the test. Then create implicit object to obtain and release a BodyContent object:
and initialize your custom tag using the pageContext implicit
object. After setting up the tag, call the tag life-cycle methods in tag.setPageContext(pageContext);
the correct order and verify the results. The tag’s output can be tag.doStartTag();
inspected in the endXXX method. // if the doStartTag method return EVAL_BODY_TAG
Complete the following to set up the custom tag for testing: BodyContent bodyContent=pageContext.pushBody();
1. Create the custom tag and initialize it with the pageCon- tag.setBodyContent(bodyContent);
text implicit object: tag.doInitBody();

MyTag tag=new MyTag(); bodyContent.println(“Sample content”);


// pageContext is available as an implicit object to JspTestCase
tag.setPageContext(pageContext); tag.doAfterBody();
tag.doEndTag();
2. Set the tag’s attributes:
pageContext.popBody();
tag.setNum1(“10”);
tag.setNum2(“11”); Implement the endXXX method to verify whether the tag
returns the expected body content or not.
3. Set the parent tag (optional):
Testing Filter
Tag.setParent(enclosingTag); Your test case class should extend from FilterTestCase when
you want to test servlet filters. Cactus automatically provides
The “enclosingTag” will have to be instantiated and set up the implicit object filterChain (FilterChain), in addition to all
as well. This will allow the tag to successfully call the method the servlet implicit objects, to the setUp, testXXX, and tearDown
getParent. methods. In your test method, do the following:
4. Create the BodyContent object (optional): If the tag pro- 1. Instantiate the Filter class.
cesses its body, call pageContext.pushBody() to obtain a 2. Set up the required request parameters.
BodyContent and the corresponding pageContext.pop- 3. To simulate the next filter in the filter chain, define a mock
Body() after the tag completes execution. filter chain inner class.
5. Set up page state (optional): Set up appropriate objects into 4. Invoke the doFilter method. Pass the mock filter chain
the request or pageContext for use by the tag. object as a parameter to doFilter if you need to verify if the
filter is returning to the correct filter in the chain.
Once the tag has been set up, test the tag by calling its relevant
life-cycle methods and using JUnit assert API to verify the results. Testing EJB
EJBs can be tested from any of the Cactus redirectors. From the
Verifying Individual Methods testXXX method, obtain the home reference to your EJB, create an
You can verify a tag that conditionally includes its body instance of it, invoke the method to test, and finally assert the result.
based on some values:
Running Cactus Tests
tag.setValueThatResultsInIncludingBodyContent(“Correct Value”); Cactus provides a ServletTestRunner to run the Cactus tests
assertEquals(Tag.EVAL_BODY_INCLUDE,tag.doStartTag()); using a browser. In addition to the Cactus redirectors, you’ll also
need to map this servlet in the web.xml file of your Web applica-
Verifying Tag Output tion. Once the Web application is deployed, you can run your
The custom tag output can easily be verified in the endXXX application using the URL http://server:port/webapp/Servlet
method of the test case. TestRunner?suite=SimpleTestServlet. This assumes that the class
SimpleServletTest has a static method suite that will provide the
Testing Iteration Tags test runner with a TestSuite that it can run. The test runner will
You can test a tag that repeats its body output a number of return the test results as XML data to the browser.
times as shown:
Summary
// […] set up tag state This article explored the concepts of using the Cactus frame-
int count=0; work to write unit tests for testing servlets, JSPs, filters, TagLibs,
do and EJBs.
{
count++; References
} while (tag.doAfterBody() == Tag.EVAL_BODY_AGAIN); • Apache Cactus: http://jakarta.apache.org/cactus
assetEquals(EXPECTED_RESULT,count); • JUnit Framework: http://junit.org/index.htm

30 August 2004 www.SYS-CON.com/JDJ


development time. Shrink my
Give me the technology to deliver it
Faster. Better. Easier.

Faster. Outsmart your development deadlines with AMD64 technology.

Better. Direct Connect Architecture lets you do more.

Easier. Your platform choice is simpler, since AMD64 technology


excels across a wide variety of application workloads.

Register at developer.amd.com and enter a drawing for a chance to win


an AMD64 system. See official rules for details and eligibility requirements.

© Copyright 2004 Advanced Micro Devices, Inc. All Rights Reserved. AMD, the AMD Arrow Logo, and combinations thereof, and AMD64 logo are trademarks of Advanced Micro Devices, Inc.
Interfaces

Dynamic Sorting with Java by York Davis


A reusable implementation

T
hose familiar with the java.util. EmployeeTO – Simple Version The first parameter passed to sort()
Comparator interface of the Java First, our EmployeeTO can be made is the collection object we wish to have
API realize its capabilities for sort- sortable by implementing the Compara- sorted. The second parameter is an object
ing a collection of objects based tor interface as shown in Listing 1. In of type Comparator that contains the
on an attribute of the objects in the addition to the getters and setters for ID, customized sorting logic – in this case
collection. This works well when there last name, and salary, EmployeeTO must EmployeeTO, which implements the
is only a single field in which sorting is implement the compare() and equals() Comparator interface. We certainly could
required. When more complex sorting is methods in order to meet the Compar- have passed any instance of EmployeeTO
necessary, the limitations of sorting on a ator’s requirements. These methods as the second parameter to the above
single field become obvious. What about define how EmployeeTO is to be sorted. method call. However, instead of reusing
the situation in which a user desires the The compare() method takes two pa- one of the three values initially added to
functionality to sort selectively on any rameters, both of type Object. Note that the collection, I chose to pass a new in-
field in object collection? This article compare() returns an int. This return stance of the class for purposes of clarity.
describes an implementation of the value tells the sort engine the collating A quick note on encapsulation and
Comparator interface that along with sequence equality of two attribute values responsibility assigning seems to be in
the reflection API allows an object to be from each of the object parameters order here. In this case, it makes sense
sorted dynamically on any of its publicly passed to compare(), respectively. We to encapsulate the specific compare()
accessible fields. need to write the code that performs this method sorting logic within Employee-
evaluation. The first step in compare() TO. With the information we have thus
Problem Statement is to cast the two parameters’ objects to far, EmployeeTO is the only class that
Let’s describe the problem a bit more EmployeeTO objects and extract the em- requires the knowledge of how it should
specifically. A collection of employee ployee IDs by calling the getId() method be sorted. Later, as a dynamic sort-
Transfer Objects (EmployeeTO class) on each object in turn. Now we can ing solution is provided, we’ll see this
exists. (For a description of the Transfer compare the values. There are really only sorting logic moved out of the Transfer
Object design pattern consult a software three possible outcomes that can result Object class as the sorting logic be-
design pattern book.) Each EmployeeTO from this comparison. Table 1 describes comes less specific to any one particular
in the collection is a data container object the results based on these outcomes. Transfer Object implementation.
for a single employee’s information. For The other method we must code This implementation will run but
this example, our simplified EmployeeTO is the equals() method. Although falls short when it comes to meeting
object contains only three pieces of data this method is not used for sorting, it the user’s requirements. Remember, we
– employee ID, last name, and salary. must be implemented in order to meet need to be able to sort on any one of the
A Human Resources application also the contract of the Comparator interface. three fields in EmployeeTO based on a
exists that uses this collection to display a user’s choice. And let’s not forget about
list of all employee data to HR applica- Sorting the Collection – Simple Version the ability to control the sort order.
tion users. The users of this system have The SimpleTest class in Listing 2 adds
the following requirements: three EmployeeTO objects to a List, Enhancement Options
1. Allow sorting on any field on the report then performs a sort on that Collection. Let’s think about the options that
2. Allow control of the sort order (Listings 2–5 can be downloaded from are available to improve what we have
www.sys-con.com/java/sourcec.cfm.) and meet the requirements. One option
York Davis is a senior Simple Solution Line 30 of SimpleTest calls the static is to code nested if/else statements
managing consultant at Before delving into our dynamic sort- sort() method of the Collections class to in our compare() method to allow for
ing solution that allows sorting on any
Software Architects, Inc. With actually perform the sort as follows. sorting on any field in the object based
more than 12 years in theattribute, let’s first look at a simple solu- on some field name parameter passed
software development field, tion that supports sorting on a single Collections.sort(elements, new to EmployeeTO. The problem with this
York has been using Java forattribute only. This will demonstrate EmployeeTO()); solution is that it’s difficult to maintain
more than five years and the basic behaviors of Comparator
has extensive experience and from this we’ll be able to glean the Comparison Return Value
building enterpriseimprovements we wish to make. This ID from Object 1’s collation sequence equal to ID from Object 2’s collation sequence 0
solution utilizes the more common use
application architectures. ID from Object 1’s collation sequence less than ID from Object 2’s collation sequence -1
of the Comparator interface. There are ID from Object 1’s collation sequence greater than ID from Object 2’s collation sequence 1
ydavis@sark.com two classes required to implement this. Table 1 Return values from compare() method

32 August 2004 www.SYS-CON.com/JDJ


and the code could get rather lengthy as code and simply pass an instance of this Next note how this method takes three
well. If new fields are added to Em- new class as the second parameter to parameters. The first is the collection
ployeeTO, we must update compare() Collections.sort(). object to be sorted. The second is a
appropriately. Doing this would cause several desir- string that defines the field of each
What we would really like to do is able results. First, we’ll have completely object in the collection on which sorting
invoke any given getter method of our decoupled any sorting logic from our should be performed. The last param-
Transfer Object at runtime without Transfer Objects. This is highly desirable eter is a Boolean specifying the sort
having to specifically hard code each as it decreases not only the size of each order. These three parameters are used
possible method call in the compare() Transfer Object by essentially eliminat- as arguments to create a new instance of
method. If we could do this, we could ing the need for sorting code, but also DynamicComparator that is the second
use the results of those method calls removes the need for coding individual parameter passed to the Collections.
to dynamically determine equality. In field comparison logic. Second, we’ll sort() method.
addition, it would be desirable if this have created a reusable utility class that Third, take a look at the compare()
dynamic sorting could be reused for any can be used in many different situa- method. This is where the reflection
Transfer Object. The good news is that tions where sorting is required. While code really kicks in. One of the first
this functionality can be achieved by le- reusability is not a specifically stated things we need to obtain is a refer-
veraging the reflection API and the flex- user requirement for our design, it is ence to a method object at line 43.
ibility of the Collections.sort() method. certainly desirable. We’ll use this reference to call methods
dynamically. This task is done using
Reflection Dynamic Solution the getMethod() helper method, which
The java.lang.reflect.Method class Figure 1 is a UML diagram (with obtains this value via reflection. Next,
provides the ability to invoke a method attribute and method details omitted) we need to determine the return type
of a given object based on the value that shows how the components of both of the methods we are about to call. Re-
of a string. For example, using a string the simple and the dynamic sorting member that we will need to compare
containing the value “getId”, the method solutions fit together. Really, the only the attribute values of the two objects
getId() of EmployeeTO can be dynami- portion that has changed since our passed into compare(). If the return type
cally invoked at runtime. This string simple solution is where the Compara- is an int, for instance, we’ll certainly
value can then be changed as we wish to tor interface gets implemented. In the have to write different code to do the
cause any of the methods of Employ- first example, EmployeeTO implement- comparison than if the return type is a
eeTO to be called. ed Comparator directly. Now Dynamic- string. Once we have the return type,
The reflection API provides a variety Comparator implements Comparator we examine it and, based on its value,
of interesting features including the and contains an intelligent implemen- dynamically perform the actual method
ability to pass parameters to methods tation of the compare() method that invocation and resulting comparison of
and the ability to determine method can be used by any class that requires a the two values.
return types. (For a complete list of collection of objects to be sorted. Note that currently there are three
these capabilities, consult the Java separate “if” test blocks – one each for
API Javadoc.) We will need the latter DynamicComparator
capability as the three getter methods Listing 3 shows the completed code
of EmployeeTO return different types listing for DynamicComparator. There
and it will thus be necessary to be aware are a number of interesting things about
of which type we have when doing the this class. First, note the class signature.
comparison in the compare() method. The class implements two interfaces
For example, we’ll need to code a differ- – Comparator and Serializable. Com-
ent sort of equality test on an int return parator should come as no surprise
value as opposed to a string. since that interface is the essence of the
sorting capabilities we desire. Also, al-
java.util.Collections.sort() though not a requirement, the API docs
A dynamic solution will also need recommend that any class implement-
to take advantage of the flexibility of ing Comparator implement Serializable
the Collections.sort() method. Recall as well.
that in our simple sorting solution we Second, look at the static sort()
passed an instance of an object that method. Classes wishing to utilize Dy-
implemented the Comparator interface namicComparator will call this method
as the second parameter to Collections. rather than Collections.sort(). I’ve
sort(). In that case, it was the Employ- decided to make sort() static to mimic
eeTO object that contained the sorting the Collections.sort() method. Although
logic. This worked great for what we the DynamicComparator.sort() method
needed it to do. Now, however, we want is called statically, internally Dynam-
something a bit more sophisticated and icComparator creates an instance of
flexible. What if we were to create a class itself. This is necessary in order for
that implemented Comparator, which it to provide access to the nonstatic
was separate from each Transfer Object? compare() and equals() methods of the
In it we could place our dynamic sorting Comparator interface that it supports. Figure 1 UML diagrams for simple and dynamic sorting scenarios

www.SYS-CON.com/JDJ August 2004 33


Interfaces

string, int, and double. The implemen- capitalizing the first character of the created a reusable, loosely coupled API
tation requires comparison logic for passed value. For instance, construct- that can be used to sort a collection of
any method return type we expect to MethodName() would convert “salary” objects based on getter methods. The
encounter. For the range of return types to “getSalary”. sort field is easily configurable and also
in our EmployeeTO example, these Last, the equals() method is needed allows control over the sort order.
three are sufficient. However, addi- to complete the interface requirements. This design, however, is not with-
tional code would need to be added to out trade-offs. Although using the
DynamicComparator if comparisons EmployeeTO – Enhanced Version reflection API allows us to do lots of
of other types are required – short, java. Listing 4 shows the enhanced ver- cool things, using reflection can slow
util.Date, java.math.BigDecimal, etc. sion of EmployeeTO. The most obvious performance. This is particularly true
Coding for each specific return type change is that EmployeeTO is now in applications using pre-1.4 versions
here is unavoidable as there is no way to even simpler than before. Now that all of Java. In addition, it’s possible that
dynamically cast Java objects. Similarly, of the sorting logic has been moved to applications wishing to sort very large
Java-supplied nonobject data types like DynamicComparator and the class no collections may find DynamicCom-
int, long, and double use entirely differ- longer implements Comparator, we parator too slow.
ent comparison operators than do first- don’t need to implement the compare() Other inadequacies of DynamicCom-
class object types like String or Date. and equals() methods. parator might become evident as well.
There are some other important Although it allows sorting on any one
points about this code. First, Dynamic- Sorting the Collection – attribute of a collection of objects in an
Comparator fully supports null values. If Dynamic Version easily configurable manner, Dynam-
either or both of the arguments passed Listing 5 is the code for Dynamic- icComparator does not address the
to compare() are null, this method Test. The only change between this class potential need to sort by multiple fields
knows how to handle the situation ac- and SimpleTest is how the sort is called. – primary and secondary field sorts
cordingly. Second, look at each return Here we pass the three parameters to like that occur automatically with the
statement within compare(). Remember DynamicComparator.sort() (Collec- ORDER BY clause in Structured Query
the requirement that the user be able to tion Object, the decapitalized attribute Language (SQL).
control not only the sort field but also name, and sort ascending flag) and let
the sort order? This code supports the the DynamicComparator do the rest. Conclusion
latter by essentially reversing the default DynamicTest could just as easily have This article introduced a reusable
sort order with a call to getSortOrder(). sorted on last name by passing “last- implementation of the Comparator
This is done if the user has decided Name” or on employee ID by passing interface that utilizes Java reflection to
to sort the result in descending order “id” as the second parameter on line 29. dynamically sort a collection of objects
based on the Boolean value passed into on any one of any number of fields
the constructor from the sort() method. Solution Discussion within that object.
Third, the constructMethodName() Building a class such as Dynamic- If your application or framework
method converts a Transfer Object Comparator has many benefits in an has a need for this specific functional-
attribute name string into a method application that requires robust sorting ity, perhaps this design will fit your
name by prepending a “get” string and capabilities. In this design, we have needs.

Listing 1 public void setId(int i) {


package simple; id = i;
}
import java.util.Comparator;
import java.io.Serializable;
public int compare(Object o1, Object o2) {
EmployeeTO emp1 = (EmployeeTO) o1;
public class EmployeeTO implements Comparator, Serializable {
private int id; EmployeeTO emp2 = (EmployeeTO) o2;
private String lastName;
private double salary; int id1 = emp1.getId();
int id2 = emp2.getId();
public int getId() {
return id; if (id1 == id2) return 0;
} if (id1 < id2) return -1;
if (id1 > id2) return 1;
public String getLastName() {
return lastName; return 0;
} }

public double getSalary() { public boolean equals(Object o) {


return salary; return true;
} }

public void setLastName(String string) { public String toString() {


lastName = string; return "id="+ id +
} " lastname="+lastName+
" salary="+salary;
public void setSalary(double d) {
}
salary = d;
}
}

34 August 2004 www.SYS-CON.com/JDJ


JNI

Calling Java from C by Michael Havey


A framework for easier JNI

T
hough most Java developers such a program, e.g., “myCtoJProgram. A C-to-Java JNI Design: The Zip Example
think of the Java Native Inter- exe”, shown in Figure 2. Interestingly, The launcher is the best-known
face (JNI) as a framework for the famed SDK C program known as example of a C program that uses
developing native libraries that the “launcher” (java.exe on Windows, the JNI’s C-to-Java interface; its pur-
can be called from Java, relatively few Java on Solaris) is written in just the pose is to house a JVM and boot-
know that JNI also supports com- same way (for more, see sidebar JNI strap a Java application on the JVM
munication in the reverse direction: Case Study: Java Launcher). Complet- by calling the application’s main
it provides native programs written in ing the picture are native libraries, such method. Other, less obvious exam-
C with the ability to call Java objects. as “myNative.dll”, whose functions can ples are C programs that require
However, the coding is thorny; logic be called from Java; these libraries are functionality whose best or only
that can be coded readily in a few lines linked to the runtime process alongside implementation is Java objects
of Java requires several times more the JVM. that must be called “in process.”
lines of C, thanks to JNI’s granular
programming model and peculiar Step Description JNI Usage
approaches to exception handling 1 Initialize the JVM JNI_CreateJavaVM(), preceded
and garbage collection. This article by several lines of code to set
explores the nature and typical use of up JVM arguments.
the C-to-Java JNI interface and pres- 2 Get references to classes ZipFile, ZipEntry FindClass().
and Enumeration Remember JVM expects
ents the design of a framework that
package names using slashes
eases the programming effort.
instead of dots (e.g., java/util/
Enumeration rather than java.
The JNI Architecture util.Enumeration).
As Figure 1 illustrates, JNI is actually a 3 Get references to several methods: ZipFile constructor, GetMethodID(). Method
pair of APIs: ZipFile.entries(), ZipEntry.getName(), Enumeration.has signatures are expressed in an
• “JNI Proper” supports the manipula- MoreElements(), Enumeration.nextElement(). unusual notation understood
tion of Java objects and classes, such by the JVM (e.g., “()Z” means
as the ability to call object methods. “returns a boolean”).
• The Invocation API is a smaller C 4 Instantiate ZipFile NewStringUTF() to convert C
library that enables C programs to string to Java string, New
create and destroy a Java Virtual Object() to instantiate, New
Machine (JVM). GlobalRef() and DeleteLocalRef()
to get global reference to zip
file object.
A C-to-Java program (that is, a C pro-
5 Call ZipFile.entries() CallObjectMethod() to call the
gram that uses Java) calls the Invocation
method, NewGlobalRef() and
API to create a JVM, and calls JNI Proper DeleteLocalRef() to get global
to use Java objects. As for the Java-to-C reference to enumeration
direction (not discussed in this article), object.
Java code calls a native method, which 6 In loop, exit when Enumeration.hasMoreElements() CallBooleanMethod()
is implemented as a C native library returns false.
function; the C code uses JNI to inter- 7 Get next element, expecting ZipEntry object CallObjectMethod()
pret its Java input types and build its 8 Call ZipEntry.getName() CallObjectMethod() to call the
Java output types. method, GetStringUTFChars()
Michael Havey The JVM is packaged as a shared and ReleaseStringUTFChars() to
is a BEA consultant library (“jvm.dll” in the Sun SDK on convert Java string to C string.
with nine years of Windows platforms and “libjvm.so” on 9 Cleanup FreeGlobalRef() to release
ZipFile and ZipEntry objects,
industry experience, Solaris) and exposes JNI Proper and the
DestroyCurrentThread() and
mostly with application Invocation API as public exports. As a
DestroyJavaVM() to destroy JVM
integration. runtime entity, a JVM is really just the
connection.
JVM library linked to an executable C
mhavey@bea.com program. Any Java developer can code Table 1 Summary of C code to list contents of a zip file

36 August 2004 www.SYS-CON.com/JDJ


Examples include programs that: <<call>>
Invocation API
• Create, extract, or list the contents create JVM
destroy JVM
of zip files. The Java SDK java.util. attach current thread
detach currrent thread
zip package is the most suitable API
available. C Native Library
<<call>> <<call>>
• Transform XML to XML, HTML, or JNI Proper: C-to-Java Program
load classes
instantiate objects
PDF. Though C XML APIs exist, Java’s call class and object methods
get/set object and class fields
support for XML is vastly superior. manage exceptions
manage object references
Launching a JVM to do XML with string and array helpers
Java is a plausible strategy for a C
<<call>>
program. <<uses>>

• Call an Enterprise JavaBean (EJB). Java Code

The C program uses JNI to execute


standard EJB client-side logic. Figure 1 C to Java, Java to C with JNI

The example of listing the contents of Listing 2 shows the code for steps 7 and forms complex logic on behalf of the
a zip file highlights the coding challenge 8; the JNI calls in lines 5, 10, 15, and 21 C code. The C code need only call the
of C-to-Java JNI. (Source code for this are followed by calls in lines 7, 11, 16, proxy.
article can be downloaded from www. and 22 to the checkException() function 2. C Façade: Hide JNI’s peculiar pro-
sys-con.com/java/sourcec.cfm.) The (implementation not shown), which in gramming model in a C façade library.
Java code to perform this logic, shown turn calls the JNI exception handling Have the C program call the façade
in Listing 1, is trivial: line 4 instantiates functions ExceptionCheck(), Excep- rather than JNI directly. In addition,
the class ZipFile in java.util.zip, passing tionDescribe(), and ExceptionClear() build proxy support into the façade;
the zip file name to the constructor; to swallow and report Java exceptions expose façade functions to call the
lines 5–9 loop over a java.util.Enumera- triggered by the JNI calls. proxy.
tion of java.util.zip.ZipEntry objects The C code in the zip example can be
getting, in line 8, the name of each entry made easier and less cumbersome by The proxy and façade constitute
in the zip file. using two design patterns: an abstract framework for use in any
Developing the equivalent logic in C 1. Java Proxy: Put the hard code where program resembling the zip program.
requires hundreds of lines of code. The it belongs, on the Java side. Develop Java proxies implement the interface
main steps are summarized in Table 1. a Java object, called a proxy, that per- shown in Listing 3; the execute()

Tools that help you understand and


maintain impossibly large bodies of
source code.

www.SYS-CON.com/JDJ August 2004 37


JNI

method is defined generically as accept- If the C zip program were to call Listing 1: Java code to list contents of a zip file
1 import java.util.zip.*;
ing an input, performing some action or the proxy using JNI directly, its length 2 import java.util.Enumeration;
set of actions, and returning an output. would be shorter but the complexity 3
4 ZipFile zf = new ZipFile(zipFileName);
Listing 4 shows the proxy implementation of JNI would remain. Using the façade 5 Enumeration entries = zf.entries();
6 while(entries.hasMoreElements())
for the zip example. The execute() method reduces the length even further and 7{
8 String entry = ((ZipEntry)(entries.nextEle-
expects as input a string specifying the shields the code from JNI oddities. A ment())).getName();
name of the zip file (line 26); it imple- design for the façade is depicted in 9}

ments logic similar to that in Listing 1 to Figure 3. The façade consists of a set
Listing 2: Excerpt of C code to list contents of zip file
enumerate the entries in the zip file (lines of data types, modeled as C struc- 1 int zipEntry(char *csEntryName)
2{
26–33) and returns a string containing the tures, and a set of functions. The data 3 jboolean isException;
4 jstring jsEntryName;
name of the entries in a pipe-delimited types represent entities such as JVM 5 jobject oZipEntry = (*jni)-
list (see lines 30–32 and 35). The method (cjJVM_t), class (cjClass_t), method (cj- >CallObjectMethod(jni, oZipEntries,
6 midEnumNextElement);
could also have returned an array or Java Method_t), and object (cjObject_t). The 7 isException = checkException();
8 if (isException || oZipEntry == NULL) return
collection type, but the calling C program functions are operations performed on 0;
9
is likely happier parsing a string than con- the entities (e.g., cjJVMConnect() and 10 jsEntryName = (*jni)->CallObjectMethod(jni,
tending with JNI array or collection class cjJVMDisconnect() performed on the oZipEntry, midZipGetName);
11 isException = checkException();
iteration logic. JVM), and a special set of proxy opera- 12 if (isException || jsEntryName == NULL)
return 0;
13 else
Method JNI Usage Description 14
15
{
const char *tempData =(*jni)-
CjJVMConnect JNI_CreateJavaVM Creates a JVM based on options specified >GetStringUTFChars(jni, jsEntryName, 0);
16 isException = checkException();
by the caller. 17 if (tempData == NULL || isException)
return 0;
CjJVMDisconnect DetachCurrentThread, Destroys the JVM. 18
19 // copy to caller's buffer and release the
DestroyJavaVM UTF
CjClassCreate FindClass, GetMethodID Gets a reference to a given Java class and 20 strcpy(csEntryName, (char*)tempData);
21 (*jni)->ReleaseStringUTFChars(jni, jsEn-
references to each of the methods specified tryName, tempData);
22 isException = checkException();
by the caller. 23 return (!isException);
CjClassDestroy Cleans up resources created in cjClassCreate() 24 }
25 }
CjProxyClassCreate See cjClassCreate Gets a reference to a Java class that
implements the JavaProxy interface. The Listing 3: CJProxy
implementation calls cjClassCreate() passing 1package cj;
2
the name of the class that implements the 3 public interface CJProxy
4{
interface and the names and signatures of 5 public Object execute(Object args) throws
Exception;
the init, shutdown and execute methods of 6}
JavaProxy.
CjProxyCreate NewObject, NewGlobalRef, Instantiates a JavaProxy class and acquires Listing 4: Java zip proxy
1 package cj.example;
DeleteLocalRef a global reference to it. 2
CjProxyDestroy See cjFreeObject Releases global reference to the proxy 3 import cj.CJProxy;
4 import java.io.*;
created in cjProxyCreate(). 5 import java.util.zip.*;
6 import java.util.Enumeration;
CjProxyExec CallObjectMethod, NewGlobalRef, Invokes the execute() method of the 7
8 /**
DeleteLocalRef JavaProxy object created in cjProxyCreate(). 9 * CJZipList is a CJProxy that lists the entries
Acquires a global reference to the object in a zip file.
10 */
returned by the execute() method. 11 public class CJZipList implements CJProxy
12 {
CjFreeObject DeleteGlobalRef Releases the global reference to an object. 13 /**
CjProxyExecString NewStringUTF, cjProxyExec, Get- Calls the proxy’s execute() method, 14 * Proxy execute takes a string with the
name of the zip file.
StringUTFChars, ReleaseStringUTF- passing a Java string, converted from the 15 * It returns a pipe-delimited string with
the list of entries
Chars C string passed by the caller. The execute() 16 * in the zip file.
method returns a Java string, which the 17 */
18 public Object execute(Object args) throws
function converts to a C string and returns Exception
19 {
to the caller. 20 if (!(args instanceof String))
21 {
Table 2 CJ C API Functional Description 22 throw new RuntimeException("Invalid
type for execute");
23 }
24
25 StringBuffer retbuf = new
StringBuffer("");
26 ZipFile zf = new ZipFile((String)args);
myNative.dll 27 Enumeration entries = zf.entries();
28 while(entries.hasMoreElements())
Java.exe 29 {
myCtoJProgram.exe 30 String entry = ((ZipEntry)(entries.
nextElement())).getName();
31 retbuf.append(entry);
jvm.dll 32 retbuf.append("|");
33 }
34
35 return retbuf.toString();
36 }
37 }
Figure 2 JNI Components: JVM, native libraries, programs

38 August 2004 www.SYS-CON.com/JDJ


tions. Table 2 describes and lists the JNI
usage of each of the C functions. <<c struct>>
cjClass_t <<c struct>>
Listing 5 is the complete source code cjMethod_t
-jvm : cjJVM_t
of the C zip program that uses the proxy -className : cstring -name : cstring
and façade. (Listing 5 can be downloaded -methods : cjMethods_t -sig : cstring
1 * -jniMethodID : jmethodID
from www.sys-con.com/java/sourcec. -jniClass : jclass

cfm.) The program launches a JVM (line


26), gets a reference to the proxy class
(line 29), instantiates it (line 33), and
calls the execute() method (line 36). The
remaining code (lines 40–50) cleans up <<c struct>>
cjJVM_t <<c struct>>
the proxy object and class and destroys cjObject_t
-argc : int
the JVM. -argv : cstringArray -class : cjClass_t
-jniJavaVM : JavaVM -jniObject : jobject
jniJNIEnv : JNIEvn
Conclusion
Hosting the hard logic in a Java proxy
and wrapping JNI calls to the proxy in a
C façade reduces the complexity of C-to- <<interface>>
CJ C API
Java programming with JNI.
+cjVMConnect(inout jvm : cjVM_t) : int
+cjVMDisconnect(inout jvm : cjJVM-t) : int
References +cjClassCreate(inout class : cjClass_t) : int
• “Java Native Interface Specification,” +cjClassDestroy(inout class : cjClass_t) : int
Sun Microsystems: http://java.sun. +cjFreeObject(in jvm : cjJVM_t, in object : object) : int
+cjProxyClassCreate(inout class : cjClass_t, in className : cstring, in jvm : cjJVM_t) : int
com/j2se/1.5.0/guide/jni/spec/jni- +cjProxyCreate(inout proxy : cjObject_t) : int
TOC.html +cjProxyExecute(in proxy : cjObject_t, in inData : jobject, out outData : jobject) : int
+cjProxyExecString(in proxy : cjObject_t, in inData : cstring, out outDatat : cstring) : int
• “Tutorial on JNI,” Sun Microsystems:
http://java.sun.com/docs/books/tuto-
rial/native1.1/concepts/index.html Figure 3 C to Java, Java to C with JNI

www.SYS-CON.com/JDJ August 2004 39


JNI

JNI Case Study: Java Launcher


Every Java developer who uses the Sun SDK is grateful for 11 5571 micro seconds to LoadJavaVM VM type selected by the caller (corresponding
12 JavaVM args:
the C program known as the launcher (its executable name is 13 version 0x00010002, ignoreUnrecognized is to “-client” or “-server” launcher command-line
“java”), which uses the JNI Invocation API to create a JVM, load JNI_FALSE, nOptions is 6 options) is one of the allowable types listed in
14 option[ 0] = '-Djava.class.path=.'
a Java class into the JVM, and call its main() method, thereby 15 option[ 1] = '-Djava.class.path=src' the file JREPath\lib\Arch\jvm.cfg (on my machine
launching a Java application on behalf of the caller. If the 16 option[ 2] = '-Xms32m' “Arch” is “i386”). If the caller did not specify a JVM
17 option[ 3] = '-Xmx64m'
launcher did not exist, a good C developer with JNI knowledge 18 option[ 4] = '-Dmy.property=1' type, the launcher defaults to the first type listed
could write an equivalent program in less than a week. 19 option[ 5] = '-Dsun.java.command=com.mike. in jvm.cfg (on my machine it’s “client”). The JVM
Hi arg1 arg2'
The launcher’s source code is available from Sun and 20 125113 micro seconds to InitializeJVM path on Windows is JREPath\bin\JVMType\jvm.
is packaged with the SDK (version 1.4.2_04, which can be 21 Main-Class is 'com.mike.Hi' dll (e.g., JREPath\bin\client\jvm.dll for the client
22 Apps' argc is 2
downloaded from http://java.sun.com/j2se/1.4.2/down- 23 argv[ 0] = 'arg1' JVM).
load.html). In the base directory of the installed SDK is 24 argv[ 1] = 'arg2' 2. Load the JVM dynamically: Whereas most programs
25 32937 micro seconds to load main class
a file called src.zip. If you extract that file, the exploded 26 ----_JAVA_LAUNCHER_DEBUG---- let the operating system implicitly link shared librar-
“launcher” directory contains the four source files that ies to their processes, the launcher, which allows the
constitute the launcher program: java.h, java.c, java_md.h, The launcher begins by finding the JRE (line 2) and the user to specify at runtime which version of the JVM
and java_md.c. The launcher’s source code is unmistakably right JVM (lines 3–10), and then loads the JVM dynamically library to use (the “-client” or “-server” command-line
C: murky, idiomatic, and circuitous. On the other hand, (line 11); as we’ll see, this logic is platform dependent. In arguments to the launcher), explicitly loads the JVM
the end result is a functional program that has been run this case, because we didn’t name a specific JVM when library using a platform-specific interface. The logic
successfully innumerable times by innumerable users. calling the launcher, the launcher defaults to “client” (more resides in java_md.c’s LoadJavaVM() function. On
Understanding how it works is a case study in the use of JNI. on this below). Lines 12–19 show the arguments that the Windows, this function calls the Win32 LoadLibrary()
Suppose there is a class called Hi in the package com. launcher will pass to the JVM; these correspond to the to load the JVM DLL and link it to the launcher pro-
mike that has a public main() method and thus can be arguments passed to the launcher. In line 20, the launcher cess, and then calls the Win32 GetProcAddress() func-
started as a Java application through the launcher. The starts the JVM. The class whose main method that launcher tion to get a pointer to the invocation API function
following is the source code: will call is given on line 21; the arguments passed to it are JNI_CreateJavaVM() used in step 4.
shown in lines 22–24. 3. Prepare JVM runtime options based on command-
1 package com.mike;
2 The launcher’s logical design (as of version 1.4.2_04) is line options passed to the launcher: Command-line
3 Public class Hi depicted in Figure 4. options such as –D, -X, and -classpath are assembled
4 {
5 public static void main(String args[])
into an array to be passed to the JVM. The launcher
6 { <<C code>>
java.c
<<C code>>
java_md.c
adds an additional property for use by the JVM of
7 … <<uses>>
8 }
the form -Djava.sun.command=class arg1 arg2 …,
+main() +CreateExecutionEnvironment()
9 } +ReadKnownVMs() +LoadJavaVM() where class is the fully qualified name of the target
+CheckJVMType() +GetArch()
+MemAlloc()
<<uses>>
+GetApplicationHome() class and “arg1 arg2 …” is the list of command-line
The Hi application is started under SDK 1.4.2_04 on arguments to be passed to its main method.
Windows 2000 with the following commands: 4. Create the JVM: The launcher calls the JVM’s JNI_Create-
Figure 4 Launcher design JavaVM() function, passing the options prepared above.
1 set JAVA_HOME=c:\j2sdk1.4.2_04
2 set _JAVA_LAUNCHER_DEBUG=true The launcher consists of two modules: java.c, which 5. Load the target class into the JVM by calling the JNI
3 %JAVA_HOME%\bin\java -classpath src -Xms32m -
Xmx64m -Dmy.property=1 com.mike.Hi arg1 arg2 contains the main function of the launcher program FindClass() method: The launcher first replaces dots
as well as platform-independent helper functions, and with slashes in the class name (e.g., it converts com.
Line 3 calls the launcher executable Java in the bin direc- java_md.c, which houses platform-specific functions. mike.Hi to com/mike/Hi) because the JVM expects
tory of my SDK (which, as line 1 indicates, is c:\j2sdk1.4.2_ The modules share a bidirectional dependency: slashes instead of dots.
04). The arguments passed to the launcher are: func-tions in java.c call java_md.c and vice versa; for 6. Call the main method of the target class: First, the
• -classpath src: Look for my “Hi” class in the directory src. example, main() in java.c calls CreateExecutionEnviron- launcher gets a reference to the main() method by
• -Xms32m: Set its minimum heap size to 32MB. ment() in java_md.c, which in turn calls ReadKnown- calling the JNI GetStaticMethodID() function, passing
• -Xmx64m: Set the maximum heap size to 64MB. VMs() in java.c. the class reference acquired in step 5, the method
• -Dmy.property=1: Make a property available to the appli- The source code in java_md.c is different for each name (“main”), and the signature (“([Ljava/lang/
cation with the key my.property and value 1. SDK platform release. For example, the Windows SDK String;)V”, the JVM’s peculiar representation of a
• com.mike.Hi: Run the application in this class. has the Windows version of java_md.c but does not void method that accepts an array of java.lang.String
• arg1 arg2: Pass arguments “arg1” and “arg2” to the have the Solaris version. If you want to see both (as I did objects). Second, the launcher calls the method via
application’s main method. as I was writing this article), you must download both CallStaticVoidMethod(). The launcher prepares the
releases. string array method input using some of the JNI’s
Line 2 sets an environment variable called _JAVA_ The main steps in the launcher’s processing are the array functions (NewObjectArray(), SetObjectArrayEle
LAUNCHER_DEBUG, which causes the launcher to gener- following: ment()), and handles exceptions in the main method
ate debugging output to the console at runtime: 1. Create the execution environment: The CreateEx using JNI’s ExceptionOccurred(), ExceptionDescribe(),
1 ----_JAVA_LAUNCHER_DEBUG---- ecutionEnvironment() function, implemented in and ExceptionClear().
2 JRE path is c:\j2sdk1.4.2_04\jre java_md.c, is a platform-specific search for the 7. Shutdown the JVM: This is done by calling the
3 jvm.cfg[0] = ->-client<- JNI DetachCurrent-Thread() and DestroyJavaVM()
4 jvm.cfg[1] = ->-server<- JRE path, JVM path, and JVM type for use by the
5 jvm.cfg[2] = ->-hotspot<- launcher. The Windows version looks up the JRE functions.
6 jvm.cfg[3] = ->-classic<-
7 jvm.cfg[4] = ->-native<-
path in the registry (on my machine, the registry
8 jvm.cfg[5] = ->-green<- key HKEY_LOCAL_MACHINE\Software\JavaSoft\Java A mystery to many Java developers, the launcher
9 1306 micro seconds to parse jvm.cfg
10 JVM path is c:\j2sdk1.4.2_04\jre\bin\client\
Runtime Edition\1.4\JavaHome is C:\Program Files\ is nothing more than a little C program that uses the
jvm.dll Java\j2re1.4.2_04), and then checks whether the J JNI to initiate a Java application.

40 August 2004 www.SYS-CON.com/JDJ


Desktop Java Viewpoint

Swing Low, Swing High,


Joe Winchester
Desktop Java Editor Sweet Desktop

S
un has made two significant box to work with data. The JForm class, is not that the unskilled developer will
announcements recently in the for example, is a nicely thought-out use this in preference to cutting Java
Java desktop space: Java Desktop control that helps you easily create a source code. Presumably, said person is
Integration Components (JDIC) data-bound set of components. What’s going to be using a GUI builder–like tool
(https://jdic.dev.java.net) and Java nice about the Swing extensions is that that should be able to hide XML or Java
Desktop Network Components (JDNC) they can be used without the rest of implementations equally well. XML,
(https://jdnc.dev.java.net), both of JDNC and, with the sorting and filtering however, offers the advantage of being
which are open sourced under an LGPL. enhancements, represent a nice turn easy to create and manipulate at run-
of the crank for Swing that any GUI time, so GUI behavior can be manipu-
JDIC developer will hopefully benefit from. lated dynamically (perhaps the XML
JDIC is essentially about allowing Another welcome feature is an overhaul prepared by a servlet as the result of a
Swing access to more native platform of the way actions work, allowing more user query) and less hard coding need
resources, such as embedding the op- flexibility. I believe there might be plans occur in the actual client layer. One
erating system’s Web browser in a GUI, to roll the Swing extension packages of the goals of any large business GUI
or enabling more control over taskbar into a future release of J2SE. Such a application must be to capture as much
support. I think the goal of elevating move would be great for the general as possible in rules and rely less on
the function point of the end-user’s Swing developer and would provide a hard-coded, bespoke client screen logic.
experience, so that a Java application welcome set of base enhancements. Having XML prepared by a rule engine
looks and behaves no differently for that consumes a model definition of the
other desktop programs, is wonderful. JDNC Components application and serves this up to JDNC
I won’t belabor the obvious point, but These mirror the Swing extensions to implement the wiring logic might
for me JDIC is a missed opportunity for with the prefix JN, so for JXTable there is well be the answer. This could become a
bringing Swing and SWT toolkits closer JNTable, JEditor has JNTable, and so on. very powerful usage scenario.
together, as the latter already provides These are standard JavaBeans so they
native embedded browser and taskbar should be easy to integrate into GUI Open Source
support. Both toolkits have farther to builders and intuitive to Java program- JDNC has been released as an open
travel along this road, as users demand mers; however, rather than subclass source project, which is interesting
more and more platform fidelity from their visual peers, they wrap them because it’s outside the usual JSR/JCP
their programs. All I sincerely hope, for instead. I think this is a great decision, process. I’m very encouraged by this,
Java’s sake, is that the decision to forgo and is rooted in the desire to simplify as I hope it will benefit from the rapid
the chance to use the CPL open sourced the programming model that currently progress that other open source proj-
SWT as the basis for JDIC was made for includes a lot of low-level properties for ects have enjoyed, and because the end
sound business reasons, not bruised Swing controls. By using delegation, the users of JDNC are programmers trying
egos. API that’s surfaced for the developer is to build business applications using
one designed around the data binding Swing. It’s an invitation for everyone
JDNC and access capabilities of the control. who has done this for the last few years
Java Desktop Network Components is There are some nice new listener to bring the benefit of their knowledge,
a project that has always promised to be interfaces as well, such as org.jdesktop. gripes, suggestions, and, ultimately,
successful because its roots lie in trying swing.event.ProgressSource that allows code to the table. If you’ve had to build
to simplify the programming model of a DataSource to signal the progress and your own data access framework on
writing GUIs that connect to back-end completion of a long-running task. The top of Swing, or wished one was there,
databases or services. By implement- whole experience using the JNCompo- I strongly encourage you to visit the
ing JDNC, developers have helpfully nents shows that they have been well JDNC homepage to become involved in
adopted a layered approach. thought-out and well implemented. the project and give the developers the
Joe Winchester is a benefit of your experience and ideas. I
software developer Swing Extensions JDNC Markup Language believe JDNC is one of the most excit-
working on WebSphere The extensions include new UI The purpose of this layer is to allow ing things to come along in the GUI
development tools for classes such as JXTable, JXTree, JXEdi- the nonprogrammer to easily customize space in any language for many years,
IBM in Hursley, UK. tor, or JTreeTable. These extend the JDNC components using XML. One of and I think it has the potential to take
basic Swing toolkit to provide a set of the main benefits I can envisage with Java client programming to a whole
joewinchester@sys-con.com controls that are designed out of the the XML configuration of components new level.

42 August 2004 www.SYS-CON.com/JDJ


Feature

Java Design Patterns


for Long Lists
Providing fast performance
by Heman Robinson

I
n the late 1990s, a GUI design pattern emerged for To fix the cell size, invoke either the setFixedHeight() and
setFixedWidth() methods, or the setPrototypeCellValue()
choosing multiple objects from long lists. In GUI Design method. In “Advanced JList Programming,” Hans Muller notes
that setFixedHeight() and setFixedWidth() are useful to align a
Essentials, Susan Weinschenk, Pamela Jamar, and Sarah JList with another component. Otherwise, it’s generally more
convenient to use setPrototypeCellValue().
Yeo called this the Selection Summary pattern. In “A Dual For the prototype cell value, use the value that is largest visu-
ally. If the maximum width is known, a prototype value can be
Listbox Selection Manager” by Steve Aube, it’s also known as assigned without looping over all the values, thus saving initial-
ization time. Alternatively, if the application uses a monospace
the Dual Listbox Selection interface. In The Java Look and Feel font, a fast loop can be written to check the string lengths of all
values. Otherwise, to allow proportional fonts, anti-aliasing,
Guidelines, Advanced Topics, it is called the Add-and-Remove and other issues, check the FontMetrics as in the code below.

idiom. double width = 0;


String prototype = "";
The Add-and-Remove design pattern (shown in Figure FontMetrics fm = jList.getFontMetrics( jList.getFont());
1) has many variations. One common enhancement is to Graphics g = jList.getGraphics();
provide “Move Up” and “Move Down” buttons to reorder for( int i = 0; ( i < values.length ); i++ )
the chosen list (see Figure 2). Sometimes the chosen list is { String s = values[ i ].toString();
displayed as a table to show additional information. if( width < fm.getStringBounds( s, g ).getWidth())
My previous article (“GUI Design Patterns,” JDJ, Vol. 9, { width = fm.getStringBounds( s, g ).getWidth();
issue 7) showed how to optimize usability for this common prototype = s;
GUI design pattern. This article shows how to optimize per- }
formance for this design pattern and other GUIs that display }
long lists. jList.setPrototypeCellValue( prototype );

Java Performance Patterns Write a Custom Model


For short lists, neither the JList or the JTable are likely For many applications, fixing the cell size may provide all
Heman Robinson is a to give performance problems; Java and Swing have been the performance boost you need. If it doesn’t, the next step is
senior developer with optimized many times over the years. If your lists contain to take advantage of Swing’s flexible architecture.
SAS Institute in Cary, NC. thousands of objects though, there are some standard Java Figures 3 and 4 show portions of the JList and JTable
He holds a BS in design patterns that optimize performance. architectures. Both lists and tables allow you to replace their
mathematics from the The key to all these performance patterns is to realize default models with custom models of your own. The only
University of North Carolina that the default list and table implementations are general requirement is that your custom model implement the List-
and an MS in computer purpose. To optimize performance, you want to bypass this Model or TableModel interface.
science from the University general-purpose code by informing the JList or JTable of your The simplest way to do this is to extend AbstractListModel
of Southern California. application’s specific needs. or AbstractTableModel. These classes provide management
He has specialized in of listeners and events. Technically, to support the ListModel
GUI design and development Fix the Cell Size interface it is necessary to override only two methods in
for 15 years and has been a For example, JLists by default assume that the objects they AbstractListModel:
Java developer since 1996. contain may be of varying sizes. If your application’s objects
are all the same size, you can inform the JList of this fact. It public Object getElementAt( int i )
hemanrobinson@yahoo.com will then bypass its general-purpose, size-checking code. public int getSize()

44 August 2004 www.SYS-CON.com/JDJ


Similarly, to support the TableModel interface it’s necessary
to override only three methods in AbstractTableModel:

public Object getValueAt( int row, int column )


public int getRowCount()
public int getColumnCount()

These methods support a ListModel or TableModel that is Figure 1 Add-and-Remove Pattern


immutable: its contents can’t be changed. For an application Figure 2 Add-and-Remove pattern with “Move” buttons and table
such as the Add-and-Remove pattern, the contents must be
mutable. This requires extending the AbstractListModel with Varied Cell Size, Fixed Cell Size, Fixed Cell Size, Fixed Cell Size,
methods to add and remove values from the list: Objects DefaultListModel DefaultListModel ArrayList Model Array Model
1,000 11 2 2 2
public void addElement( Object o ) 2,000 21 2 2 2
public void removeRElement( int i ) 5,000 50 2 2 2
10,000 104 2 2 2
Similarly, the AbstractTableModel can be extended with 20,000 208 2 2 2
methods to add and remove rows from the table. 50,000 500 2 2 2
100,000 1070 3 3 3
public void addRow( Object[] row ) Table 1 JList “Add” Performance, in Milliseconds
public void removeRow( int i )
Varied Cell Size, Fixed Cell Size, Fixed Cell Size, Fixed Cell Size,
Writing a custom model informs the Swing GUI control Objects DefaultListModel DefaultListModel ArrayList Model Array Model
of your application’s specific needs, causing it to bypass its 1,000 7 7 1 1
general-purpose code. For example, both the DefaultListModel 2,000 15 15 1 1
and the DefaultTableModel are Vector based. This means their 5,000 35 35 3 2
accessor methods are synchronized. If your application doesn’t 10,000 76 80 6 2
require synchronization, it can be removed in the custom 20,000 157 155 11 5
model, for example, by using an ArrayList instead of a Vector. A 50,000 380 380 28 11
custom ListModel based on an ArrayList is shown in Listing 1. 100,000 770 770 55 22
For the Add-and-Remove pattern, a further performance Table 2 JList “Add All” Performance, in Milliseconds
boost can be obtained by realizing that the total number of ob-
jects never changes. Both Original and Chosen lists have a fixed Objects DefaultTableModel ArrayList Model Array Model
maximum size, which is the sum of the number of objects in 1,000 2 2 2
each. This means that a custom model does not need expand- 2,000 2 2 2
able storage, such as a java.util.Collection, so a more efficient 5,000 2 2 2
array can be used instead. A custom TableModel based on an 10,000 2 2 2
array is shown in Listing 2. 20,000 2 2 3
Finally, significant performance can be gained by adding 50,000 3 3 3
methods to the custom model to process multiple objects. 100,000 3 3 3
The custom ListModel of Listing 1 provides three methods to Table 3 JTable “Add” Performance, in Milliseconds
handle multiple objects:
Objects DefaultTableModel ArrayList Model Array Model
public void addAll( Object[] objects ) 1,000 7 1 1
public void clear() 2,000 15 2 1
public Object[] toArray() 5,000 38 3 1
10,000 78 6 2
In the DefaultListModel, to add 100 objects addElement() 20,000 160 13 5
must be invoked 100 times. In the custom model, the addAll() 50,000 385 35 11
method can be invoked only once. If an application oper- 100,000 770 75 22
ates on multiple objects, performance can almost always be Table 4 JTable “Add All” Performance, in Milliseconds
improved by writing a custom model.
The performance boost from a custom renderer is roughly
Can More Be Done? proportional to the number of objects being rendered. If your ap-
For most applications, a custom model provides sufficient plication displays only a few objects, as in the Add-and-Remove
performance improvement. However, Swing provides another pattern, this performance boost is not significant. A better use of
option using the same architectural pattern. As shown in Fig- a custom renderer is given by Steve Wilson and Jeff Kesselman in
ures 5 and 6, JList and JTable rely on renderers to display their Java Platform Performance: Strategies and Tactics. Their example
contents. displays a sparse table that derives a significant performance
Just as the custom model replaced the default model, a boost because the empty cells don’t need to be rendered at all.
custom renderer can replace the default renderer. The only Some highly specialized applications require more special-
requirement is that the custom renderer implement the List- ized performance patterns. Hans Muller notes that internally
CellRenderer or TableCellRenderer interface. JList uses the toString() method to convert objects to strings. If

www.SYS-CON.com/JDJ August 2004 45


Feature

the application does not need this generality, the conversion • Muller, H. (2000). “Advanced JList Programming”: http://
time can be saved by building a custom model around the java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.
String class rather than the Object class. html
In Christmas Tree Applications Scott Violet and Kathy • Sun Microsystems Inc. (2002). Java Look and Feel Design
Walrath give a fine and detailed example using a custom ren- Guidelines: Advanced Topics. Addison-Wesley Professional:
derer and other performance patterns. Their code produces http://java.sun.com/products/jlf/at/book/Idioms6.html
fast performance for frequently updated JTables. Patterns • Violet, S., and Walrath, K. (2002). “Christmas Tree
such as these are not usually needed, but they show the per- Applications”: http://java.sun.com/products/jfc/tsc/arti-
formance improvements that become possible when Swing cles/ChristmasTree/
is tailored to a specific application. • Weinschenk, S., Jamar, P., and Yeo, S. (1997). GUI Design
Essentials. Wiley & Sons. p. 192, 206–207.
How Much Improvement Can We Expect? • Wilson, S., and Kesselman, J. (2000). Java Platform
Performance benchmarks for the Add-and-Remove pattern Performance: Strategies and Tactics. Chapter 10: http://java.
show that fixing the cell size is the most cost-effective perfor- sun.com/developer/Books/performance/
mance pattern for JLists. Both JLists and JTables can achieve
dramatic improvement from custom models, especially when Listing 1
processing multiple objects.
/** Custom ArrayList model */
The benchmarks shown in Figures 7 and 8 and Tables 1–4 private class CustomArrayListModel extends
AbstractListModel
were run using JDK 1.4.1 under Mac OS X on a G4 CPU at {
/** @serial List */
450MHz. Your mileage will vary, but these conclusions hold for private ArrayList _list;
most applications: /**
• For a JList, fix the cell size. * Returns specified object.
* <p>
• For a long list or table, write a custom model. * @param i index
* @return object
• For a specialized application, consider specialized design */
patterns such as a custom renderer. public Object getElementAt( int i )
{ return( _list.get( i ));
}

Conclusion /**
* Returns size of list.
The Add-and-Remove GUI design pattern enables users to * <p>
* @return size
choose multiple objects from long lists. Appropriate Java de- */
sign patterns provide fast performance for this GUI and other public int getSize()
{ return( _list.size());
applications. }

/**
Resources * Adds the specified element to the end of the list.
* <p>
• Aube, S. (2000). “A Dual Listbox Selection Manager”: * @param o Object
*/
www.codeguru.com/Cpp/controls/listbox/article.php/ public void addElement( Object o )
{ _list.add( o );
c4755 fireIntervalAdded( this,
_list.size() - 1, _list.size() - 1 );
}

JList ListModel JTable TableModel /**


* Removes the specified element.
* <p>
AbstractListModel
* @param i index
AbstractTableModel
*/
public void removeElement( int i )
{ _list.remove( i );
DefaultListModel DefaultTableModel fireIntervalRemoved( this, i, i );
}

Figure 3 JList and ListModel Figure 4 JTable and TableModel /**


* Adds all of the specified elements.
* <p>
* @param objects Array of Objects
JList ListCellRenderer JTable TableCellRenderer */
public void addAll( Object[] objects )
{ for( int i = 0; ( i < objects.length ); i++ )
_list.add( objects[ i ]);
DefaultCellRenderer DefaultTableCellRenderer fireIntervalAdded( this, _list.size() -
objects.length, _list.size() - 1 );
}
Figure 5 JList and ListCellRenderer Figure 6 JTable and TableCellRenderer
/**
* Removes all objects from the list.
1200 800 */
public void clear()
1000
600
{ int size = _list.size();
800
_list.clear();
Milliseconds
Milliseconds

Varied Cell Size Default Model fireIntervalRemoved( this, 0, size - 1 );


600 400 }
400
ArrayList Model /**
200
200 Array Model * Returns list as array.
* <p>
Fixed Cell Size
0 0 * @return list
0 25000 50000 75000 100000
0 25000 50000 75000 100000
*/
Objects Objects
public Object[] toArray()
{ return( _list.toArray());

Figure 7 JList “Add” Performance Figure 8 JTable “Add All” Performance

46 August 2004 www.SYS-CON.com/JDJ


} }

/** /**
* Constructor. * Adds all of the specified rows.
* <p> * <p>
* @param size size of list * @param objects Array of rows
*/ */
public CustomArrayListModel( int size ) public void addAll( Object[][] objects )
{ _list = new ArrayList( size ); { System.arraycopy( objects, 0,
} _table, _rows, objects.length );
} _rows += objects.length;
fireTableRowsInserted(
Listing 2 _rows - objects.length, _rows - 1 );
}
/** Custom array model */
private class CustomArrayModel extends AbstractTableModel /**
{ * Removes all rows.
/** @serial Data vector */ */
private Object[][] _table = new Object[ 0 ][]; public void clear()
{ int rows = _rows;
/** @serial Column names */ _rows = 0;
private Object[] _columnNames = new Object[ 0 ]; fireTableRowsDeleted( 0, rows - 1 );
}
/** @serial Number of rows */
private int _rows = 0; /**
* Returns table as array.
/** * <p>
* Returns specified value. * @return size
* <p> */
* @param row row index public Object[][] toArray()
* @param column column index { Object[][] objects = new Object[ _rows ][];
* @return value System.arraycopy( _table, 0, objects, 0, _rows );
*/ return( objects );
public Object getValueAt( int row, int column ) }
{ return( _table[ row ][ column ]);
} /**
* Constructor.
/**
* <p>
* Returns number of rows.
* <p> * @param rows maximum number of rows
* @return number of rows * @param objects data vector
*/ * @param columnNames column names
public int getRowCount() */
{ return( _rows ); public CustomArrayModel( int rows,
} Object[][] objects, Object[] columnNames )
{ _table = new Object[ rows ][];
/** System.arraycopy( objects, 0,
* Returns number of columns. _table, 0, objects.length );
* <p> _rows = objects.length;
* @return number of columns _columnNames = columnNames;
*/ }
public int getColumnCount() }
{ return( _columnNames.length );
}

/**
* Returns row as array.
* <p>
* @param i row index
* @return row
*/
public Object[] getRow( int i )
{ return( _table[ i ]);
}

/**
* Returns column names.
* <p>
* @return column names
*/
public Object[] getColumnNames()
{ return( _columnNames ); Google, the world leader in large-scale information retrieval, is
}
looking for experienced software engineers with superb design
/**
* Assigns data and column names. and implementation skills and considerable depth and breadth in
* <p>
* @param objects data vector the areas of high-performance distributed systems, operating
* @param columnNames column names
*/ systems, data mining, information retrieval, machine learning,
public void setDataVector(
Object[][] objects, Object[] columnNames ) and/or related areas. If you have a proven track record based on
{ System.arraycopy( objects, 0,
_table, 0, objects.length ); cutting-edge research and/or large-scale systems development
_rows = objects.length;
_columnNames = columnNames; in these areas, we have plenty of challenging projects for you in
fireTableRowsInserted( 0, _rows - 1 );
} Mountain View, Santa Monica and New York.
/**
* Adds the specified row to the end of the table.
* <p> Are you excited about the idea of writing software to process a
* @param row row
*/ significant fraction of the world's information in order to make it
public void addRow( Object[] row )
{ _table[ _rows ] = row; easily accessible to a significant fraction of the world's population,
_rows++;
fireTableRowsInserted( _rows - 1, _rows - 1 ); using one of the world's largest Linux clusters? If so, see
}
http://www.google.com/cacm. EOE.
/**
* Removes the specified row.
* <p>
* @param i index
*/
public void removeRow( int i )
{ System.arraycopy( _table, i + 1,
_table, i, _rows - i - 1 );
_rows--;
fireTableRowsDeleted( i, i );

www.SYS-CON.com/JDJ August 2004 47


DOI

A GUI Painter Friendly


Table Component by Gunnar Grim

The principle of the column container

I
n the early days of Java, GUI There is, however, a completely area is an ordinary panel with a flow
forms were written, not drawn. different way to go, which is the layout in which column components
They were created by writing code one I chose for the table component can be dropped and reordered. The
that instantiated components in our own class library DOI, called columns must be instances of the
and added them to containers with the DoiTable. DoiTableColumn class. If you ac-
various layout constraints. Then the cidentally drop some other type of
program was run and the result could Design Time Behavior component inside it, the drop area
be admired. This way of working, The DoiTable doesn’t have a turns red.
WYGIWYG (what you get is what you table model property editor at all. A DoiTableColumn is a direct
get) was often quite fun, more often In fact, when you drop it on the descendant of the DoiTextField class,
frustrating, and never very produc- form it doesn’t even look like a which is the standard text field in the
tive. Today we have a JavaBeans speci- table. Instead, it behaves like a DOI library, overridden to change
fication and integrated development container during design time, the design time appearance and
environments (IDEs) with GUI paint- and you fill it with columns by add some properties and behavior
ers. Some of these are doing really dropping DoiTableColumn compo- that is specific to a table column. As
good jobs, considering the difficulties nents inside it. At runtime, though, you can see, I’ve tried to make the
with layout managers and column components look a
platform portability. bit like the columns they will
With most components, become at runtime. From the
such as text fields and GUI painter’s point of view,
buttons, the principle of the table is just a container.
dropping them on the form, Therefore, the painter will
setting properties, and allow you to set properties on
adding event listeners is each individual column as if
quite sufficient. The JTable they were ordinary fields on a
though is more problematic. panel, which is exactly what
It’s just too complex to con- they are, until you run the
figure with simple property application. In Figure 1, one
editors and also so common of the columns is selected so
that you don’t want to have to write a it automatically converts itself to you can see the property sheet for it
Gunnar Grim is a lot of code every time you use it. a JTable with all the column prop- in the lower right pane. Note also that
programmer, designer, You can drop a table in a JScroll- erties taken from the design time the column components retain their
and architect for the Pane and set a lot of properties on the column components. preferred size even if the table is too
consulting firm Know IT JTable, but when it comes to adding Figure 1 shows the design time narrow to show them all on one line.
(www.knowit.se). He has and customizing columns, the GUI look of a simple table with four col- The fourth column, “Logical”, doesn’t
been in the business for painter can’t help you since the col- umns. The screenshot is taken from fit, so it’s placed on a new row. This
20 years, programming umns are not JavaBeans. One solution the NetBeans form editor. When the behavior is consistent with any other
in everything from Z80 is for the GUI painter to provide an designer drops a table on the form, flow layout panel. Although I could
assembly code to SQL editor for the table model property, it appears as a big rectangle. The de- have made them resize themselves to
Windows. Since early 1996 thereby letting you define columns signer can then give the table a label mimic the behavior of a JTable more
he has worked almost and set a few attributes on them. and activate tools for inserting and closely, I decided against it to make
exclusively with Java, mostly However, I have never seen an editor deleting rows by setting properties on the columns easier for the designer to
on the server side but also that will allow you to customize the the table. Note the “Table” label and work with.
quite a lot with Swing. columns of the table with the same small tool bar above the rectangle. This is basically how the table com-
flexibility you have when you custom- The rectangle is the drop area for ponent presents itself to the designer.
gunnar.grim@knowit.se ize text fields on a form. columns. During design time this To the user, however, it looks just like

48 August 2004 www.SYS-CON.com/JDJ


a JTable in a JScrollPane, as shown in bd.setValue(“isContainer”, The first thing the method does
Figure 2. I’ll shortly go into the details Boolean.TRUE); is invoke the same method on
on how this conversion happens, but bd.setValue(“containerDelegate”, the superclass to let it do whatever
first a little bit about how the table “getColumnContainer”); it needs to do, then it calls the
component communicates with the method commitColumnContainer
GUI painter. return bd; to do the real work. This method
} looks like:
Adjusting the BeanInfo
Every JavaBean component that The method creates a BeanDescrip- public void commitColumnContainer()
you can draw on a form must have a tor, which is an object that contains {
supporting BeanInfo object, which is basic properties about the bean. commitColumnContainer(false);
an instance of a class that implements While some of these properties have }
the java.beans.BeanInfo interface. The dedicated methods such as setName,
BeanInfo object is used by the GUI others are set using the generic set- As you can see, it doesn’t do much;
painter to determine which properties Value method. In the code above, the it just delegates to another method.
and events the bean has. Although it property isContainer is set to TRUE to The reason for this is that the other
can be created automatically using tell the GUI painter that although this method has a parameter that allows
introspection, it’s usually written by bean isn’t empty, it is still a container. the caller to force a conversion even if
the author of the bean. Writing such a We also have to tell the GUI painter we are in design time. This is useful in
class is outside the scope of this arti- which method on our bean returns certain circumstances, which I’ll get
cle, but there is one important feature the inner container by setting the back to later. For now we’ll look at the
that is often forgotten when BeanInfo property containerDelegate to the first few lines of the “real“ commit-
classes are described: the “container name of the method. In the DoiTable ColumnContainer method:
delegate” property. At the time of case, the method is called getColumn-
writing it isn’t even mentioned in the Container. public void commitColumnContainer(
Java Tutorial. Without this property, all boolean pForce)
beans must fall into the following two Converting to Runtime Behavior {
categories: When the application is run we if (!pForce && Beans.isDesignTime())
1. Component beans such as JTextField obviously don’t want the table return;
or JButton – you drop them in con- to look like it does in the GUI if (itsColumnContainer == null)
tainers but you don’t drop anything painter. Instead we want the return;
inside them. drop area, a.k.a. the column
2. Simple container beans such as container, to convert itself to
JPanel – they are initially empty and a real JTable. This conver-
you can drop components inside
them.
sion happens in the method
addNotify, which is called auto- WHO’S
The GUI painter can tell them apart
matically on every component
when it is added to a display-
DEVELOPING
by treating empty containers as cate- able container. This method THE COOLEST
gory 2 and all other beans as category
1. The DoiTable, however, falls into a
may be called several times,
so we must make sure the
WIRELESS
third category. It isn’t just a container, table doesn’t attempt to con- APPLICATIONS?
but a container that initially has a la- vert itself more than once.
bel, a tool bar, and an inner container
for the columns. Without a special
Also, we don’t want it to con-
vert itself at all when we are YOU ARE!
“trick” in the BeanInfo class, the GUI using the table in the GUI
painter would think that the DoiTable painter. To test for design
is an ordinary component because time or runtime mode, there
it isn’t empty and won’t let you drop is a method in the java.beans. ENTER TO WIN THE 2005 SIMAGINE
anything inside it. This is certainly Beans class called isDesign- DEVELOPERS’ CONTEST!
not the behavior we want, so we must Time. This method returns
Over $70,000 will be awarded
inform the GUI painter that it is a true when called from a com-
for innovative SIM card services
container and that it has a special ponent in a GUI painter, and
including a special Cingular award for
place for dropping stuff. The following false otherwise. best submission from North America
code excerpt from the DoiTableBean- The first thing we need to
Info class shows how this is done: do is implement the addNotify Deadline is October 10, 2004!
method:
public BeanDescriptor getBeanDescriptor() In association with:

{ public void addNotify()


BeanDescriptor bd = {
new BeanDescriptor(itsBeanClass); super.addNotify();
Full contest details at: www.simagine.axalto.com or call 1 888 343 5773
commitColumnContainer();
© Axalto 2004
bd.setName(“DoiTable”); }

www.SYS-CON.com/JDJ August 2004 49


DOI

The method starts by checking if for (int i = 0; i < ccc; ++i) { The scroll pane will eventually con-
a conversion should happen at all by DoiTableColumn column = tain a JTable, but before we can create
testing the force parameter and calling (DoiTableColumn)itsColumnContainer it we need a column model, the object
the isDesignTime method. If these tests .getComponent(i) used by Swing’s JTable to represent its
are passed, it goes on to check if the itsColumns[i] = column; columns. A JTable can automatically
table has already been converted. The column.setTable(this); create the column model based on its
column container panel is created and } table model, but we don’t want that
added to the table by the constructor because the DoiTableColumn objects
and removed when the conversion is Each column is given a reference contain much more information about
completed. This means that if it is null, back to the table using the setTable the columns than is contained in an
the table is already converted and the method of the DoiTableColumn class. ordinary table model, e.g., preferred
method returns immediately. Now the This reference is used by the column width in characters, resizability, label
real conversion can be done. We start off to access various properties on the text. etc.
by transferring all column beans from table that affect its behavior. Now it’s The below code creates a column
the column container into an internal time to get rid of the column container model that contains column objects of
array: and replace it with a scroll pane: Swing’s TableColumn class, with rel-
evant properties copied from the cor-
int ccc = remove(itsColumnContainer); responding DoiTableColumn objects:
itsColumnContainer.getComponentCount(); itsColumnContainer = null;
itsScrollPane = new JScrollPane(); TableColumnModel colmod =
itsColumns = new DoiTableColumn[ccc]; add(itsScrollPane, BorderLayout.CENTER); new DefaultTableColumnModel();

for (int i = 0; i < ccc; ++i) {


// Get the column bean. Skip if hidden.
DoiTableColumn column = itsColumns[i];
if (column.isHidden())
continue;
// Create a Swing column.
TableColumn swingColumn =
new TableColumn();
// Copy properties.
swingColumn.setHeaderValue(
column.getLabelText();
swingColumn.setResizable(
column.isResizable();
// Add to column model.
colmod.addColumn(swingColumn);
}

There is still one little detail before


Figure 1 Design Time we can create the JTable. We need
a table model. A JTable can’t exist
without a table model so we need to
create one that is initially empty. This is
accomplished with the following code:

TableModel tm =
new DefaultTableModel(0, ccc);

Now the JTable can be created and


added to the scroll pane that has
replaced the column container. We
also tell it not to automatically create a
new column model if the table model
is replaced later:

JTable jt = new JTable(tm, colmod);


jt.setAutoCreateColumnsFromModel(false);

Figure 2 Runtime itsScrollPane.add(jt);

50 August 2004 www.SYS-CON.com/JDJ


That’s it. The DoiTable bean now set programmatically. It is also sary. This check is IDE dependent,
contains a JTable within a JScrollPane updated automatically when the and in the NetBeans case it is done
instead of a column container panel. user selects a row. I mentioned by searching the parent container
The DoiTableColumn beans still ex- earlier that the DoiTableColumn hierarchy for the innermost frame
ist though, and there is an implicit class is a subclass of a class called that has a title starting with “Testing
association between each column DoiTextField, which is an enhance- Form[”. Other IDEs will
bean with the corresponding Swing ment of JTextField. This means that most likely need variations of this
TableColumn object in the column a DoiTableColumn bean can have a technique.
model. This association will prove value. The context row is used to syn-
very useful for later enhancements, chronize the value of a column bean Conclusion
some of which I’ll hint at in the next and the corresponding cell value. I hope I’ve provided you with some
section. The designer can add a listener on ideas that you can use when you write
I promised to mention the pur- a column bean that’s triggered your own beans. The same principle
pose of the pForce parameter. This when the user edits the cell. The can naturally be applied to very dif-
parameter can be used by subclasses event handler can then access ferent kinds of widgets, especially
of the DoiTable that create and add all the cell value through the column complex ones that are easier to design
columns. Let’s say you want to create a bean and set a value on another cell with if they are broken up into parts.
bean called PhoneNumberTable, with on the same row, also through a col- The time spent on doing this is earned
a number type column and a phone umn bean. The code for this is easier many times over when the end-user
number column. This bean would to write and maintain than using a GUIs are designed.
add its columns in the constructor table model listener.
and then call commitColumnCon- Resources
tainer(true) to force the conversion to Design Time Rendering • The Java Tutorial, trail JavaBeans:
a JTable. In this case, the force param- As you can see in Figure 1, the http://java.sun.com/docs/books/
eter is necessary since the conversion text fields in the column beans tutorial/javabeans/index.html
must happen in design time as well as are not empty. Instead they • NetBeans FAQ – GUI Editing: www.
runtime. contain a text value that reflects netbeans.org/kb/faqs/gui_editing.
a few important properties (a feature html
Enhancements inherited from the base class
The purpose of this article is to DoiTextField): a mandatory
show you the principle of the column column has an exclamation
container, not how to write a full- mark suffix, a numeric column
fledged table component. To do that, is displayed with “#”, “##” or
I’d probably have to fill 10 issues of “#.#” (depending on if it is an
JDJ. For this reason the code examples Integer, Long, or Double), an
shown of what really happens inside uppercase string column uses
the DoiTable have been simplified. “ABC”, etc.
Still, I’d like to round off with a brief
list of some interesting features in the Smart Design Time Checking
real DOI classes. In some circumstances,
checking for design-time
Runtime Propagation of Properties mode is not sufficient. Some
Many of the DoiTableColumn prop- IDEs, for example, NetBeans,
erties are automatically propagated to have a preview function
the JTable when changed at runtime. that creates a window with
This allows runtime code to dy- the form inside it where the
namically change the table by simply designer can try it out. The
setting properties on the DoiTable- isDesignTime method still
Column bean, which is much easier returns true, however, which
than doing it through the JTable. For causes DoiTable to think that
example, the column header is up- it’s still in design mode, and
dated if the label text of the column is it doesn’t convert itself. To get
set. This propagation is accomplished around this, it has its own is-
through the implicit association be- DesignTime method that first
tween the invisible column bean and calls the standard method. If
the visible table column. it returns false we are in “real”
runtime, and no further check-
Runtime Synchronization of Cell Values ing is necessary; if it returns
The DoiTable has a property called false an extra check for the
ContextRowNo that can be special preview mode is neces-

www.SYS-CON.com/JDJ August 2004 51


Feature
POI

Unlocking Microsoft
Office Documents
by Ryan Ackley and
Avik Sengupta

An open source alternative

I
f you’ve ever written software to the Excel record structures (HSSF) or the row create the cells you need. Finally,
be used by business managers, Word record structures (HWPF). populate the cells with the data. As List-
you will no doubt have received ing 2 shows, a cell can contain integers,
requests for interoperability with HSSF floats, strings, and dates.
the Microsoft Office Applications. “Get HSSF is the component of POI that
me the report in Excel; HTML doesn’t allows you to read, write, and manipu- Styles
cut it and I need to run my own analysis late Excel spreadsheets from pure Java All that is fine, but plain data is usu-
on it”; “Can you index the zillion word applications. It consists of code that ally not sufficient to keep your users
documents I have so that the whole understands the Excel record formats, happy. HSSF therefore has a whole
organization can search on them?”; and wraps them up in an easy-to-use range of features designed to let you use
“I have all this data in Excel; do I have API. a variety of styles and formats that Excel
to enter it again on this Web page?”…. How easy does HSSF make reading supports.
These are things we commonly hear Excel files? See for yourself! To start applying styles to cells, first
as application developers, which is not create an instance of an HSSFStyle class:
surprising given the ubiquity of MS InputStream in = new
Office. FileInputStream("data.xls")); HSSFStyle myStyle = wb.createCellStyle()
Does this mean you’re forced to HSSFWorkbook wb = new // wb is an HSSFWorkbook object
tie your application to Windows to HSSFWorkbook(in);
interface with the COM APIs of Excel HSSFSheet sheet = wb.getSheetAt(0); The style object will now provide
or Word? Apart from the fact that you // the 1st sheet you with methods to set various style
don’t want your language or platform HSSFRow row = sheet.getRow(1); parameters, such as foreground and
decision to be constrained by a lack of // get the 2rd row background colors, fonts, borders, and
choice, it’s also important to note that HSSFCell cell = row.getCell((short)1); data formats, via conventionally named
these APIs can be unstable because // the 2nd cell of the 2nd row setters.
Ryan Ackley they’re automating a desktop applica-
has been an active tion. Because of this, they are unreliable The model of an Excel document in Data Formats
contributor to the POI for any server-side deployment. For the HSSF begins with the HSSFWorkbook A key component of a cell’s style is its
project for several years. Java developer, however, the power of object. This object provides access data format. This specifies, for example,
Jakarta POI is close at hand. to the sheets (by name or number), the number of decimal places in a
sackley@cfl.rr.com POI is a pure Java application library which in turn provides access to the number, or the format of a date. The
for reading and writing the Microsoft rows (HSSFRow) in the sheet. Each row data format is set using the setDataFor-
OLE2 Compound Document Format provides access to the individual cells mat method of HSSFStyle. This method
(OLE2CDF) file formats. This format is (HSSFCell) it contains. takes an integer, which is an index to
used by (among others) various MS Of- From the cell object you can retrieve a format, since Excel keeps a list of
fice applications. As the name suggests, data contained in that cell via acces- indexed built-in formats (and user-de-
this is a format for storing multiple sor methods, depending on the type of fined formats are appended to this list
documents (or streams) in one file, for data. Listing 1 provides an example. and indexed in a similar fashion).
example, storing an embedded spread- Given this object model, writing is It’s easy to get the index, however.
Avik Sengupta is a sheet along with a presentation. Within equally simple. Instead of “get”-ing rows For a built-in format, use the static
domain committer this structure are stored the records that and columns, you “create” them and getBuiltinFormat method in the HSSF-
on the Jakarta POI contain the application-specific data. then “set” the values in the cells as in DataFormat class. Give it the format
project, and is chief POI is structured along these lines. At Listing 2. string and it will return the correct
technology officer at its base it has a component known as Once again, start with the HSSFWork- index, the proper index for you. To set
Itellix Software the POIFS or the POI File System, which book class, whose default constructor a format:
Solutions. is the most complete implementation of provides a new workbook object; then
the OLE2CDF structure in Java. Layered populate the workbook by creating a myStyle.setDataFormat(HSSFDataFormat.
avik@apache.org above this are the components to read sheet in which you create rows. In each getBuiltinFormat(“d-mmm-yy”);

52 August 2004 www.SYS-CON.com/JDJ


For a user-defined format, first get formula in the resultant sheet correctly, loaded with data, charts, and pivot
an instance of HSSFDataFormat from you might want to use absolute refer- tables. Listing 3 provides an example.
an HSSFWorkbook object to ensure ences instead of relative. If formulas with Hopefully this overview of HSSF has
that your format is registered with the relative cell references (the default, e.g., convinced you that HSSF has almost all
workbook: A1) are copied from one cell and pasted to it takes to create professionally produced
another, the cell references in the formu- Excel spreadsheets that’ll be a joy to your
HSSFDataFormat df = las change relative to the destination cell. users, and leave them asking for more.
wb.createDataFormat();
myStyle.setDataFormat(df.getFormat(“dd%M cell.setCellFormula(“A1/$A$25”); Word Documents with HWPF
MM%yyyy”)); The HWPF (Horrible Word Process-
However, if the formula contains refer- ing Format) component of POI is a Java
If you don’t want to worry about ences that are absolute, they stay the library for reading and writing Word
which formats are user defined (it’s same irrespective of the destination cell. documents. It’s still in early beta but is
documented in the Javadocs for HSSF- Absolute references are specified by add- relatively stable and it is the only open
DataFormat), simply use the nonstatic ing a $ symbol to the reference, viz. $A$1. source Java solution we know of for
method and it will take care of this issue Note that the row and the column can be programmatically accessing and/or
internally. individually addressed while specifying creating a Word document.
When you have defined the style you absolute references, viz. A$1 vs $A1. I am going to give a short introduc-
want, just set it to the cell: You can also reference other sheets tion to the high-level structure of a Word
in the same workbook in the formula. document. These are basic concepts
cell.setCellStyle(myStyle); HSSF does not yet support the ability that can be applied to most styled docu-
to write formulas referencing external ment formats and they will make later
Reuse the same style object for cells workbook files. sections of this article easier to digest.
that are similarly formatted – do not A Word document can be modeled as
create new style objects for each cell, Cell.setCellFormula(“SUM(Sheet1!A1- a tree-like structure. Figure 1 illustrates
since Excel has an upper limit on the Sheet1!A2)”); // formula in cell A1 of this. The document has sections, a sec-
number of styles that can be referenced Sheet2. tion has paragraphs, and a paragraph
in a workbook. For example, you could has character runs. Each instance of
create one style object for the table Note, however, that the formula results these is associated with a range of text.
headers, one for the body, and one for are not calculated by HSSF, which is • A section can be correlated with a
the footer and use them throughout really a file format reader and writer, not chapter in a book. A section contains
your spreadsheet. a functional replacement for a spread- obscure properties like the page bor-
sheet application. The formula is merely der and the number of columns.
Formulas written into the file in the proper format
Probably one of the most important and evaluated when the file is opened in A Guide to POI Versions
features of HSSF is the ability to popu- Excel.
late cells with formulas. This allows you As an open source project, POI’s development is carried out in a public re-
to create dynamic spreadsheets and Finally pository by a group of volunteers. As a result, the code is quite dynamic, and
facilitate the user’s ability to change Among other advanced features, HSSF this guide will help you navigate the multiple versions you’ll find in the wild.
the data and perform her own analysis allows you to create merged cell regions. In general, note that releases with beta, dev, or RC attached to their names
(which is indeed the power of spread- You can also set headers and footers for are flagged as development releases, while releases without these postfixes
sheets, and the number one reason why sheets, as well as set print areas, to ensure are flagged as production releases.
you would want to output Excel files). the data prints well. You can create split The 1.5.1 version released early 2002 was the preferred production version
for a long time. But after a long series of new features, followed by a longer
Formulas are created using the set- and freeze panes, set zoom options, or
period of bugfixes and stabilization, the 2.0 version was released in January
CellFormula method of an HSSFCell ob- enable sheet protection. Additionally,
2004.
ject. The input to this method is a string you can create and manipulate named
Subsequently, the 2.5 version was released in late February 2004 to
containing the formula you want at that ranges. Later versions (see sidebar – A
incorporate a major new piece of functionality – the ability to create drawings
cell. It should be in the same format that Guide to POI Versions) also let you pro-
in Excel sheets via what is known as the Escher Layer.
you would type into the edit box in Excel grammatically create drawings in sheets. Meanwhile, development had been ongoing in an experimental branch to
(without a leading “=”), thus: However, there are always features enable the reading and writing of Word documents (HWPF). Unfortunately,
of an Excel file that POI does not yet it’s necessary to download this piece of POI directly from CVS and compile it
cell.setCellFormula(“A1+A2^2”); support. In such scenarios, templates yourself. There are many excellent and free client applications for accessing
are invaluable. The idea is to create an CVS repositories such as WinCVS and jCVS.
You could use any built-in VBA func- empty Excel spreadsheet populated
tion, or even a user-defined function, in with the attributes that POI doesn’t
the formulas: support. You could, for example, create Getting Started
a chart in the spreadsheet referencing
Cell.setCellFormula(“average(A1:B1)”); named ranges, or create a pivot table in Getting started with POI couldn’t be easier. Download the version you
cell.setCellFormula(“mySpecialFunction(A a certain area. At runtime, in Java code, want from www.apache.org/dyn/closer.cgi/jakarta/poi/ as a zip or tar.gz
1/A2)”); you could read the workbook in with archive. From the archive extract poi-<version>-<date>.jar. Add this file to your
POI and fill in the cells with data from classpath and you should be set. POI has an optional dependency on log4j,
If you need to provide your users with your application. Now when the user but that’s needed only if you turn on logging (which is disabled by default).
the ability to copy-paste or drag an Excel opens the workbook in Excel, it comes

www.SYS-CON.com/JDJ August 2004 53


POI

• A paragraph follows the traditional Paragraphs(), and numCharacterRuns() Lists


definition of a paragraph. It contains and the correlating getters are actu- Unlike tables, lists don’t have a begin-
more familiar properties that most ally implemented in the Range class. ning and an end, because entries in
Microsoft Word users know. The jus- Of course, if you call numSections() on a list can be inserted anywhere in the
tification (left, center, right) and the a Paragraph object, it will return one. document and the list numbering can
indent setting are good examples. That would be the parent Section of that pick up wherever it left off. The ListEntry
• A character run is a consecutive run Paragraph object. class is used to represent an entry, and it
of characters that share the same Another important method in the extends the Paragraph class. Look at how
formatting. These contain the most Range class is text(). This can be used to I get a list entry in the following example:
common and visible properties. get the plain text for a particular range.
Some examples are font family, font To get the text for a document, use the 1 for (int x = 0; x < numPars; x++)
size, bold, italic, and underline. following code: 2 {
3 Paragraph par =
This provides you with enough String plainText = 4 range.getParagraph(x);
information to use Java to read and doc.getRange().text(); 5
manipulate this model. To get started, 6 if (par instanceof ListEntry))
we have to create an HWPFDocument Once we have an instance of a Sec- 7 {
object from a physical Word file. tion, Paragraph, or CharacterRun object, 8 ListEntry entry = (ListEntry)par;
we can read its properties by calling its 9
1 FileInputStream in = various getters. 10 //do something with the entry…
2 new FileInputStream(“C:\\test.doc”); 11 }
3 HWPFDocument doc = //Check the number of columns 12 }
4 new HWPFDocument(in); //for this section
Section sect = r.getSection(x); Adding New Content
The Section, Paragraph, and Charac- sect.getNumColumns(); There may be a time when you want
terRun classes represent the document to generate new Word documents or
tree that I explained earlier. I walk that //See if a paragraph is set to modify an existing document using
tree in Listing 4. //have a page break before it. Java. My first word of advice is to make
First, I get the Range object for the Paragraph par = sect.getParagraph(y); sure that this is absolutely necessary. In
entire document. This is the entry point boolean breakBefore = par.pageBreakBefore() most cases, a nonproprietary file format
to the object model. The Range class is such as PDF, RTF, or HTML is the better
an important piece of the HWPF API. It //Get the font name of a choice. There are free libraries available
represents an arbitrary range of text in //character run for all of these. In the cases of RTF and
the document, with one to many sec- CharacterRun run = HTML, the standard JDK provides the
tions, paragraphs, and character runs. par.getCharacterRun(z); javax.swing.text package to manipulate
The Section, Paragraph, and Character- String font = run.getFontName(); the file formats. A rule of thumb for
Run classes extend the Range class. creating Word documents is: Will the
The methods numSections(), num- These are quick examples. There eventual recipients of these documents
are dozens of settings and there isn’t want to edit them? If not, the PDF or
enough space to cover them all. I en- HTML format is a better choice. If they
courage you to read the Javadoc to see do wish to edit them, consider using
what is possible. RTF instead of the Word file format.
The writing functionality of HWPF is
Tables somewhat experimental so expect some
Behind the scenes, tables are just a bugs and limited features. Modifying
group of paragraphs with certain flags set. an existing document or creating a new
HWPF attempts to hide the juicy details Word document from scratch starts
but it still needs a little help (see Listing 5). the same way – simply create a new
Figure 1 Word doc modeled as a tree-like structure Listing 5 touches every paragraph in HWPFDocument as shown in an earlier
the document, looking for one with the example. The only difference is that if
table flag set. When it finds one, it passes you want to create one from scratch,
it to the getTable method on line 8. Notice you start with a blank document. The
on line 12 that it’s necessary to increment POI distribution comes with one called
x so that the paragraphs that were part of “blank.doc.”
the table aren’t processed again. To commit any changes to a physical
Tables have TableRows, which in turn file and see what they do, you must
have TableCells. All these classes extend write out the modified document. The
Range so you can use all the methods following code writes out a Word docu-
that I’ve already talked about for getting ment that contains any changes made
Figure 2 Word document the contents of these entities. to the original object model.

54 August 2004 www.SYS-CON.com/JDJ


FileOutputStream docOut = tas from a style stored in the stylesheet. HWPF only supports writing simple,
new FileOutputStream( Styles provide a convenient way to main- one-level lists. Figure 2 shows a screen-
“C:\\testout.doc”); tain a consistent look and feel in a docu- shot of the Word document created using
doc.write(docOut); ment. They also help a person creating a the code in Listing 6.
Word document through a user interface
To be safe, I wouldn’t recommend to be more efficient. To a programmer Summary
overwriting the original document. this may not matter. No matter what the POI has its weaknesses. The biggest by
HWPF attempts to keep things that it style is, whatever properties are set for far is the memory consumption in the Ex-
doesn’t directly support in the file, but a particular Paragraph or CharacterRun cel component (HSSF). The POI team has
this doesn’t guarantee that they will be object will appear in the document. I recognized this problem and is trying to
there when it writes the file out again. recommend just using the number 0 for address it in a coming release. The Word
The Section, Paragraph, and Char- a style index. This will always refer to the component’s (HWPF’s) biggest problem is
acterRun classes define setters that “Normal” style in the stylesheet. that it isn’t very mature. Right now it only
allow the various properties of existing provides very limited functionality. Even
content to be changed. The Range class Editing Tables the Excel side of POI could use improve-
defines the following methods for add- Because of the complexity, the range ment on its support of some key Excel
ing text and paragraphs to a document. class does not currently define meth- features, such as charting and images
• insertBefore(String text): Inserts ods for inserting tables. However, the If POI doesn’t cut it, there is a wide
a string into the document at the TableCell class extends Range, so all of selection of commercial libraries for
beginning of the Range. Assumes the the insert methods defined in Range can working with Excel, such as SoftArti-
properties of the character run at the be used to add content to the individual sans OfficeWriter. SoftArtisans (www.
beginning of this range. table cells of an existing Table. softartisans.com) is the only vendor I
• insertAfter(String text): Inserts a string could find that also offers a product that
into the document at the end of the Adding Lists can create Word documents in pure Java.
Range. Assumes the properties of the Adding a list is a little tricky. Unlike OfficeWriter also supports every feature
character run at the end of this range. most objects in the document, a list is of Word and Excel.
• insertBefore(String text, Character- not associated with a range of text. There With the new agreement between
Properties props): Inserts a string into are paragraphs that are associated with Sun and Microsoft, we may one day see
the beginning of the Range with the a list and these paragraphs are actual the opening of the Microsoft file formats.
properties given by props. entries in a list. Before an entry can be While you wait for this day to come, POI
• insertAfter(String text, Character- added to a document, a list must be cre- provides a free open source alternative.
Properties props): Inserts a string into ated. The following code creates a list.
the end of the Range with the proper- References
ties given by props. 1 HWPFList list = new HWPFList(true, • Apache POI: http://jakarta.apache.
• InsertBefore (ParagraphProperties 2 doc.getStyleSheet()); org/poi
props, int styleIndex): Inserts a new 3 • WinCVS: www.wincvs.org
empty paragraph at the beginning of 4 int listID = doc.registerList(list); • SoftArtisans OfficeWriter: http://
this Range. Based on the style at index officewriter.softartisans.com/office
styleIndex in the stylesheet. The HWPFList constructor takes two writer-240.aspx
• InsertAfter (ParagraphProperties arguments. The first one is a boolean
props, int styleIndex): Inserts a new determining whether the list should be Listing 1
empty paragraph at the beginning of bulleted (if the argument is false, the String value;
switch (cell.getCellType())
this Range. Based on the style at index list will be numbered), and the second is {
styleIndex in the stylesheet. the stylesheet of the document to which case HSSFCell.CELL_TYPE_FORMULA :
value = "FORMULA "+ cell.getCell-
the list will belong. The register Formula();
break;
All of the insert methods return the List method that I call on the method on
Range that the insertion is now a part of. line 4 is defined in HWPFDocument. It case HSSFCell.CELL_TYPE_NUMERIC :
value = "NUMERIC value="
For example, when inserting a para- returns a unique ID that’s needed when + String.valueOf(cell.
getNumericCellValue());
graph using insertAfter(ParagraphPrope adding a list entry to the document. break;
rties props, int styleIndex), a Paragraph The Range class defines more insert
case HSSFCell.CELL_TYPE_BOOLEAN :
object is returned. Since Paragraph methods for adding list entries. value = "Boolean value="
extends Range, all of the above methods • insertBefore(ParagraphProperties + String.valueOf(cell.
getBooleanCellValue());
can be used to fill this paragraph with props, int listID, int level, int style- break;
text. The ParagraphProperties and Index) case HSSFCell.CELL_TYPE_STRING :
CharacterProperties are similar to the • insertAfter(ParagraphProperties props, value = "STRING value="
+ cell.getStringCell-
Paragraph and CharacterRun classes. int listID, int level, int styleIndex) Value();
The difference is that classes ending break;

with “Properties” are not associated with What is different from the normal case HSSFCell.CELL_TYPE_DATE :
value = "DATE value="
a location in a document. There are also paragraph insert is that both of the + cell.getDateCellVal-
SectionProperties and TableProperties. above methods require the list ID and ue().toString();
break;
The methods that insert a paragraph the level. The level argument refers to
default :
require a style index. Paragraphs and the indent level of the list. At this point, }
character runs store their settings as del- the level argument is ignored because

www.SYS-CON.com/JDJ August 2004 55


POI

Listing 2 FileInputStream in = new FileInputStream("C:\\blank.doc");


HSSFWorkbook wb = new HSSFWorkbook(); HWPFDocument doc = new HWPFDocument(in);
HSSFSheet sheet = wb.createSheet();
Range range = doc.getRange();
HSSFRow row = sheet.createRow((short)0);
HSSFCell cell = row.createCell((short)0);
CharacterProperties props = new
cell.setCellValue(1); // cell A1
CharacterProperties();
row.createCell((short)1).setCellValue(1.2); //cell A2
row.createCell((short)2).setCellFormula(“A1+A2”); //cell // Set the font size in half points
A3 is 2.2 Range currentRange = range;
row.createCell((short)3).setCellValue("The next cell is a
boolean, and then a date"); // Slowly increase the font size
row.createCell((short)4).setCellValue(true); //cell A5 for (int x = 8; x <= 64; x += 4)
row.createCell((short)4).setCellValue(new Date()); //cell {
A6 contains todays date // Set the half point size of the font
FileOutputStream out = new FileOutputStream("data1.xls"); props.setFontSize(x);
wb.write(out);
currentRange = currentRange.insertAfter(" Hello
out.close();
World!", props);
}
Listing 3
InputStream in = new FileInputStream("data.xls")); // Display Bold characters
HSSFWorkbook wb = new HSSFWorkbook(in); // read in props.setBold(true);
existing workbook
currentRange = currentRange.insertAfter(" Bold",
HSSFSheet sheet = wb.getSheetAt(0);
props);
HSSFRow row = sheet.getRow(0);
if (row == null) row = sheet.createRow(0); // check if
// Display Italic characters
row already exists
HSSFCell cell = row.getCell(0); props.setItalic(true);
if (cell == null) row.createCell(0); // check if currentRange = currentRange.insertAfter(" Italic",
cell already exits props);
cell.setCellValue(2.5); // update
cell value // Display charcters with a Double Strikethrough
props.setDoubleStrikeThrough(true);
FileOutputStream out = new FileOutputStream("data2.xls"); currentRange = currentRange.insertAfter(" Double
wb.write(out); // and Strikethrough", props);
write it back out.
in.close; out.close(); // Insert an empty paragraph for readability
currentRange = currentRange.insertAfter(new
ParagraphProperties(), 0);
Listing 4
5 Range r = doc.getRange();
// Reset the character properties
6
7 int numSections = r.numSections(); props = new CharacterProperties();
8 for(int x = 0; x < numSections; x++) props.setFontSize(32);
9 {
10 Section sect = r.getSection(x); // Create a numbered list
11 int numPars = sect.numParagraphs(); HWPFList list = new HWPFList(true, doc.get-
12 for (int y = 0; y < numPars; y++) StyleSheet());
13 { int listID = doc.registerList(list);
14 Paragraph par = sect.getParagraph(y);
15 int numRuns = par.numCharacterRuns(); // Insert a list entry
16 for(int z = 0; z < numRuns; z++) currentRange = currentRange.insertAfter(new
17 { ParagraphProperties(), listID, 1, 0);
18 CharacterRun run = props.setIco24(0xff0000);
19 par.getCharacterRun(z);
currentRange = currentRange.insertAfter(" Blue list
20 }
entry", props);
21 }
22}
// Insert another list entry
currentRange = currentRange.insertAfter(new
Listing 5 ParagraphProperties(), listID, 1, 0);
1 for (int x = 0; x < numPars; x++) props.setIco24(0xff);
2 {
props.setFontSize(38);
3 Paragraph par =
4 range.getParagraph(x); props.setCapitalized(true);
5 currentRange = currentRange.insertAfter(" larger red
6 if (par.isInTable()) capitalized", props);
7 {
8 Table t = range.getTable(par); //Last list entry
9 currentRange = currentRange.insertAfter(new
10 //do something with the table… ParagraphProperties(), listID, 1, 0);
11 props.setIco24(0);
12 x += (t.numParagraphs() – 1); props.setCapitalized(false);
13 } props.setCharacterSpacing(150);
14}
currentRange = currentRange.insertAfter(" Large char-
acter spacing", props);
Listing 6
import java.io.*; // Write out the document
FileOutputStream out = new FileOutputStream("C:\\
import org.apache.poi.hwpf.*;
hello.doc");
import org.apache.poi.hwpf.usermodel.*;
doc.write(out);
out.flush();
public class Listing1
out.close();
{
public Listing1() }
{ catch (Throwable t)
} {
t.printStackTrace();
public static void main(String[] args) }
{ }
try
{ }

56 August 2004 www.SYS-CON.com/JDJ


Labs

VERITAS i3 for J2EE Reviewed by


Rob Halleron

S
ometimes as J2EE applica- caused by the fact that our application is desired service levels – such as the time it
tion developers we feel like we hosted by another group within our par- takes to serve page content.
are in a darkened room. We ent company. However, the rest of our ex- VERITAS i3 for J2EE provides great
know that something is wrong perience was, and remains, fantastic. We visibility into application performance
with our application, but we have no began using VERITAS i3 to test our GENIE problems through a GUI that lets you
idea where the problem is. Application holiday (vacation) booking system, and drill down from an alert to where the
performance management (APM) tools, now use it in deployment. The chief thing problem lies. For example, it under-
such as VERITAS i3 for J2EE, has helped it does is tell us when we are not meeting stands response time contributions from
us “turn on the lights” by enabling us to
see exactly where in the application our
problem really is. Once we identified the
problem, it all flowed from there, as we
could look at how the problem affected
our application from end to end and
make the right decisions on how to fix
the problem. VERITAS i3 APM software is
the only solution we found that provides
such end-to-end application visibility.

VERITAS i3 for J2EE


Application performance manage-
ment is a continuous process that de-
tects past, current, and future potential
application bottlenecks. It finds where
the problem resides by drilling down
into the application tiers to find the
problem’s root cause, and it improves
application and end-user productivity
by helping IT staff to fix problems proac- Figure 1 Overview of the Web, application, and database servers
tively, before end users are affected. Key
parts of the VERITAS i3 software suite are
VERITAS Inform, which provides alerts
and reports; VERITAS Insight, which tells
you where an application bottleneck is;
and VERITAS Indepth, which tells you
how to solve the problem.
VERITAS i3 for J2EE can quickly, ef-
ficiently, and unobtrusively capture the
Rob Halleron has beenmetrics necessary to appropriately tune
J2EE-based applications. It presents
a technical architect with
these important metrics in a manner
Lunn Poly for the past nine
that enables crisp communication, rapid
years. He was involved
detection, correction, and verification
with the definition and
throughout the application’s life cycle.
deployment of its J2EE-
and Oracle-based GENIE
holiday booking application. Installing and Using VERITAS i3
Lunn Poly is a leisure travel VERITAS i3 for J2EE loads from CDs. We
retailer in the UK with more struggled a bit trying to install and config-
than 750 retail stores. ure agents on each tier of the application
and then setting up a central “perfor-
rob_halleron@tui-uk.co.uk mance warehouse.” Perhaps this was Figure 2 The method invocation graph shows that the logon process could be investigated further

60 August 2004 www.SYS-CON.com/JDJ


Unleash the Power
of the Application Lifecycle
at the 2004 Borland Conference

The Borland Conference is a premier event for technical education, focusing on all the technologies impacting
software development. With more than 200 technical sessions, you will see how you can facilitate teamwork, enhance
productivity, improve quality, reduce costs, cut maintenance time, and accelerate business flexibility and success. Learn
how the entire development team can create and deploy better software, faster – with the integrated Borland suite of
products for the analyst, architect, developer, tester, deployment group, and manager.
Special discount of up to 50% on select Borland products • Exhibit hall • Free conference proceedings CD • Product Solution tracks covering all Borland
products, including JBuilder,® Delphi,™ Together,® StarTeam,® CaliberRM,™ C#Builder,™ C++BuilderX,™ Optimizeit™ ServerTrace, Borland® Enterprise Server,
Janeva,™ and InterBase® • Interest Area tracks, including ALM, Methods, and Processes; Architecture, Models, and Patterns; Microsoft® .NET Framework;
J2EE™; SOA; emerging technologies; and more!

September 11-15, 2004 • San Jose, California


For complete conference details and session information: connect.borland.com/borcon04
Made in Borland® Copyright © 2004 Borland Software Corporation. All rights reserved. Java and all Java-based marks are trademarks
or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries. All Borland brand and product names are trademarks or
registered trademarks of Borland Software Corporation in the United States and other countries. • 22127.5
Labs

Java servlets, JSP, EJBs, JMS, JNDI, JDBC, performing SQL statements, including item is the logon process and should
and XML. It correlates activity across Web, one particular query that was running at be quick, so this could be investigated
multiple JVMs, and DB servers. It also has 0.5 of a second but was occupying one further. The JVM etailJVM6 is also more
a SmarTune feature that gives you great entire processor. We were able to tune this heavily loaded than the others, which
advice on how to fix the problem. query down to 0.08 of a second. may indicate a balance problem.
For example, a third party wrote part of Starting at the Insight screen in Figure Clicking on the third item in the
our application that served up static con- 1, there is an overview of the three layers method invocations graphs gives more
tent about cruise holidays. These pages to the system: Web, application, and da- details (see Figure 3).
should have been delivered fast, since tabase servers. From the graph on the left, Clicking on the top item in the list digs
they can be stored in cache memory. most of the time is spent in the J2EE layer. into that particular call to reveal these
Using VERITAS i3 we found the problem We could investigate that further by choos-
was that the application was making a da- ing the J2EE option on the top menu. JDJ Product Snapshot
tabase call for each statement asking for In Figure 2, the method invocation
content. The product allowed us to find graph appears to show two high usage Target Audience: Java application architects/devel-
and fix that problem quickly. In another items but these are part of struts and so opers and application managers
instance, we were able to identify poorly will normally be high. However, the third Level: Beginner to advanced
Pros:
• Understands response time contributions from
Java servlets, JSP, EJBs, JMS, JNDI, JDBC, and XML
• Correlates activity across Web, multiple JVMs,
and DB servers
• Spans the application cycle (development, test-
ing, deployment)
• Gathers data in real time; stores historical data
• Alerts you in advance of an SLA breach
• Easy-to-use GUI
• Analysis spans entire application, from end
user to storage
• Provides advice on how to solve application-
performance problems
Con:
• Difficult installation process needs to be
streamlined (I’m told this is remedied in v7,
due to ship in Q4 2004)

VERITAS Software Corporation


Figure 3 Drilling down gives more detail on the “JVM etailJVM6” logon process 350 Ellis Street
Mountain View, CA 94043
Phone: 800 327-2232
650 527-8000 (outside U.S.)
Web: www.veritas.com

Specifications
Application Servers: BEA WebLogic Server 5.1,
6.0, 6.1 ,7.0, 8, 8.1; IBM WebSphere 3.5.x, 4.x,
5.x; Oracle 9iAS 9.0.2, 9.0.3; Tomcat 3.x, 4.x;
Macromedia JRun 3.x; Sun Java Enterprise System
Operating Systems: Sun Solaris 2.6, 7, 8, 9; IBM
AIX 4.3.3, 5.1, 5.2; HP-UX 11.0,11i; Windows NT
SP6a, 2000 SP3; Linux Red Hat 7.2, 8 Advanced
Server 2.1; SuSE Linux 8.0, Linux S/390
Pricing: Based on number of processors and server
class.

Test Environment
Sun Servers (two Web servers: 2 CPU Sun
Enterprise 280R; two application servers: 4 CPU
Sun V480; database server: F15K 6 CPU domain)
running the Solaris 8 operating system
Figure 4 Looking at routines to find out why it is using up the majority of the response time

62 August 2004 www.SYS-CON.com/JDJ


Advertiser Index
sub calls (see Figure 4). Most of the time is spent local to the routine com.
tuiuk.etail.channel.shop.agentlogon.servlet.AgentLogonServlet.service. Advertiser URL Phone Page
A developer can now investigate why it is using up the majority of the
response time. Altova www.altova.com 978-816-1600 9
If we take a step back to Figure 1, we can investigate the top Oracle state-
ment in the graph. Clicking on the top item in the bar graph and then the AMD developer.amd.com 408-749-4000 31

Oracle tab in the top menu bar takes us to the screen in Figure 5.
Axalto www.simagine.axalto.com 888-343-5773 49
We can now launch Indepth for Oracle to determine what the statement is.
As you can see in Figure 6, this is a very large INSERT statement that is part of Axosoft www.axosoft.com 800-653-0024 57,65
our content-refresh process, so it’s not unreasonable for it to take a while to
process; nothing to worry about there. Borland www.go.borland.com/j6 831-431-1000 7

Summary Borland Conference 2004 www.connect.borland.com/borcon04 61

VERITAS i for J2EE is an excellent tool to diagnose and fix J2EE appli-


3
ClearNova www.clearnova.com/thinkcap 770-442-8324 23
cation-performance issues at any point in the application life cycle.
Its ability to drill down and find the root cause of your performance Compuware www.compuware.com 35
issue is superb. If you need end-to-end visibility into your application,
this is the ideal solution. Enerjy www.enerjy.com 866-598-9876 17

Google www.google.com/cacm 650-623-4000 47

Identify Software www.identify.com 11

InferData www.inferdata.com/jdjmag 888-211-3421 25

InterSystems www.intersystems.com/match6 617-621-0600 4

Jinfonet www.jinfonet.com/yeehaw 301-838-5560 43

LinuxWorld Conference & Expo www.linuxworldexpo.com 508-424-4847 58-59

Northwoods Software Corporation www.nwoods.com/go 800-434-9820 51

Oracle www.oracle.com/platform 800-633-0753 Cover II

Parasoft Corporation www.parasoft.com/soaptest 888-305-0041 13

Quest Software, Inc. http://www.quest.com/jdj 800-663-4723 Cover IV

Rascal Software www.rascalsoftware.com/java 206-624-7300 15

Figure 5 The highest-usage Oracle statement ReportingEngines www.reportingengines.com/download/f1ere.jsp 888-884-8665 19

Scientific Toolworks, Inc. www.scitools.com 37

Sleepycat Software www.sleepycat.com/bdbje 510-597-2128 27

Software FX www.chartfx.com 800-392-4278 Cover III

Tangosol www.tangosol.com 617-623-5782 21

WebAppCabaret http://www.webappcabaret.com/jdj.jsp 866-256-7973 41

Web Services Edge 2005 East www.sys-con.com/edge 201-802-3045 39

General Conditions: The Publisher reserves the right to refuse any advertising not meeting the standards
that are set to protect the high editorial quality of Java Developer’s Journal. All advertising is subject to
approval by the Publisher. The Publisher assumes no liability for any costs or damages incurred if for any
reason the Publisher fails to publish an advertisement. In no event shall the Publisher be liable for any
costs or damages in excess of the cost of the advertisement as a result of a mistake in the advertisement
or for any other reason. The Advertiser is fully responsible for all financial liability and terms of the contract
executed by the agents or agencies who are acting on behalf of the Advertiser. Conditions set in this docu-
ment (except the rates) are subject to change by the Publisher without notice. No conditions other than
those set forth in this “General Conditions Document” shall be binding upon the Publisher. Advertisers (and
their agencies) are fully responsible for the content of their advertisements printed in Java Developer’s
Journal. Advertisements are to be printed at the discretion of the Publisher. This discretion includes the posi-
tioning of the advertisement, except for “preferred positions” described in the rate table. Cancellations and
changes to advertisements must be made in writing before the closing date. “Publisher” in this “General
Conditions Document” refers to SYS-CON Publications, Inc.

This index is provided as an additional service to our readers. The publisher does not assume any liability for errors or omissions.
Figure 6 The INSERT statement takes a while to process

www.SYS-CON.com/JDJ August 2004 63


Pressroom

Industry News
Quest Manages J2EE Performance Issues DataDirect Technologies to Enhance Sun’s Through the joint distribution agreement,
with PerformaSure 3.5 Data Connectivity Capabilities Borland will now make the eBay and PayPal
(San Francisco) – Quest Software, Inc., a (Bedford, MA) – DataDirect Technologies, Software Development Kits (SDKs) avail-
provider of application, database, and a provider of components for connecting able to JBuilder developers. The agreement
Windows management solutions, has an- software to data, has announced that Sun provides the extensive JBuilder developer
nounced the release of Quest PerformaSure Microsystems has selected its DataDirect community with access to code examples and
3.5, an application-centric diagnostics Connect for JDBC suite of drivers to expand technical resources that are designed to help
tool that helps companies tune, diagnose, the functionality and performance of the them build highly available Java applications
and resolve performance issues in multitier Sun Java Studio Creator offering and the Sun that tap into the eBay marketplace as well as
J2EE applications. Featuring new support Java System Application Server. DataDirect PayPal’s online payment services.
for J2EE application servers from Oracle, Technologies’ JDBC components will enhance www.borland.com
JBoss, and Apache, and continued support Sun’s data connectivity capabilities in both http://developer.ebay.com
for BEA WebLogic and IBM WebSphere, development and deployment environments. www.paypal.com/pdn
Quest PerformaSure 3.5 enables compa- www.datadirect.com
nies to utilize its diagnostics capabilities to Oracle Application Server 10g Enhances Inte-
identify and resolve performance issues in ILOG Acquires JLOOX Business from eNGENUITY gration with Certification of B2B Standards
complex J2EE applications, regardless of (Paris) – ILOG, a provider of enterprise-class (Redwood Shores, CA) – Oracle Application
the application servers they choose. software components and services, has an- Server 10g is certified to support all leading
www.quest.com nounced it is acquiring the intellectual property business-to-business (B2B) standards, en-
and other selected assets of the JLOOX product abling organizations to comply with industry
Sun Releases Java Platform Upgrade line for USD 1.7 million from eNGENUITY mandates required by companies such as
(Santa Clara, CA) – Sun Microsystems has Technologies Inc., a Montreal, Canada-based Cisco, Intel, Wal-Mart, Home Depot, and
announced a significant upgrade to the maker of software. JLOOX is used for the devel- Lowe’s.
Java platform and programming language. opment of advanced visual applications. By enhancing support for standards such
Known as Project Tiger, the beta release of In addition to JLOOX intellectual property, as EDI over the Internet-AS2 (EDIINT AS2)
the Java 2 Platform Standard Edition (J2SE) ILOG will acquire the JLOOX customer base and RosettaNet, Oracle Application Server 10g
5.0 aims to offer easier development, new and prospects. ILOG also plans to enter into a enables companies in the high technology,
application monitoring and management three-year OEM agreement with eNGENUITY manufacturing, retail, and consumer pack-
features, a dedicated focus on rich client that will allow eNGENUITY to continue to use aged goods industries to connect to business
support for the PC desktop, and improved ILOG’s visualization technology in its STAGE partners’ supply chains using B2B standards.
performance. products. As a result, organizations can meet integration
The J2SE 5.0 software development kit www.ilog.com mandates set forth by Cisco, Intel, and Wal-
(JDK) includes tools such as compilers and Mart by using Oracle Application Server 10g’s
debuggers necessary for developing applets Borland, eBay, and PayPal to Expand pretested connectivity tools and integration
and applications and the Java Runtime Opportunities for Java Developers features.
Environment (JRE). (San Francisco, CA) – eBay and Borland Soft- www.oracle.com
Sun also announced that Java Specifica- ware Corporation have announced an agree-
tion Request (JSR) 176 has reached final ment to provide users of Borland JBuilder with Zero G Introduces SolutionArchitect
draft through the Java Community Process tools and resources that enable them to create (San Francisco / Grapevine, TX) – Zero G
(JCP). J2SE 5.0 is based upon JSR 176. Java applications for the eBay and PayPal Software has introduced SolutionArchitect, a
www.sun.com platforms and communities. software installation and configuration solu-
tion for building ready-to-deploy software
Fiorano Is Leading EAI Product for SMB’s Report Network Computing Labs packages using the new Solution Installation
packaging standard. Designed to improve the
(Los Gatos, CA) – Fiorano Software, Inc., a provider of standards-based integration, business-process management, process of packaging software, SolutionArchi-
and enterprise messaging software and solutions, has announced that its Business Integration Suite has been tect produces self-configuring and self-heal-
chosen by the Editors of Network Computing (NWC) Labs as the best product for the mid-market EAI segment. ing software packages, and can combine
Fiorano’s Integration Suite is built on a second-generation Enterprise Service these packaged components together into
Bus (ESB), in which the logical application design is mapped directly to the complete, customized software solutions that
physical implementation, making the development process more intuitive and can then be deployed using Zero G’s multi-
easier than that of conventional integration suites. platform application deployment solution
www.fiorano.com InstallAnywhere.
www.zerog.com

64 August 2004 www.SYS-CON.com/JDJ


@ the Backpage

Unified Diversity Ted Goddard

T
he network effect is the impetus unified through common standards. integration point that gives developers
behind today’s software plat- This is not only an economic principle; and deployers choices at every stage.
forms, but a balance must be looking at software platforms, we see In opposition, .NET holds up a single
struck between homogeneous the network effect on many levels. Let's supplier, eager to collect high taxes and
vulnerability and fractured inefficiency. examine how J2EE and .NET compare. exercise control.
Comparing J2EE to .NET shows clear Everything derives from the human For the long term, the most impor-
advantages for J2EE through vendor network of education, and both J2EE tant network is that of the platform de-
diversity, portability, standardization and .NET technologies are excellent velopers. How do people work together
community, educational opportunity, starting points for an education in to define the standards and technolo-
language commonality, and security. computer science. The difference is gies that make up a platform? The Java
.NET’s attempt to replicate J2EE is shal- that only J2EE is suitable for a formal Community Process may not be as
low, providing technological similarity curriculum. Unlike the .NET unmain- fair or as open as some would like, but
in a disconnected and proprietary tained prototype in “Shared Source,” fundamentally it does provide a way for
package. J2EE code is freely available in its developers and vendors to reach a con-
Broadly speaking, the network effect entirety for educational and research sensus and participate in the evolution
is the growth experienced by networks purposes. Academic integrity is pre- of J2EE. In contrast, platforms imposed
due to the feedback loop induced by served only when full examination and by dictatorship are technology mo-

“ For the long term, the most important network is that of the
platform developers. How do people work together to define the
standards and technologies that make up a platform? ”
the increasing value of joining a grow- discourse are encouraged. nopolies, leading to lower quality and
ing network. Consider fax technology. Isn’t .NET better for teaching? With lost innovation. Herein lies the tragic
It has been successful because the net- its Common Language Infrastructure, flaw of .NET. Publishing a document
work of fax machines, connected by the it can be used to teach any language. and declaring it to be a standard omits
telephone system, communicates reli- However, this is a dangerous illusion. the peer-refinement process, and the
ably – thanks to a common standard. .NET reduces the interesting differ- technology becomes little more than a
The adoption of fax machines showed ences of programming languages to a tool of its owner.
runaway growth because, in a sense, syntactic tower of Babel. Exposure to a Finally, let’s turn to the unfortunate
Ted Goddard is a the value of a fax machine increased variety of languages is an essential part reality of our somewhat hostile world.
senior software as the size of the entire fax network of every education, but they must be Billions of years of evolution have dem-
architect at ICEsoft. increased. seen in their true form to be of value. In onstrated the catastrophes that await
Prior to ICEsoft, Such networks may start slowly, contrast, Java makes no such claim of homogeneous systems with their rep-
he held positions at but when they do succeed the effect universality; it simply unites develop- licated single points of failure. Today
Java Software, Sun is dramatic. Clearly, interoperability is ers with a common language, allowing we see this in the explosive growth of
Microsystems, in device crucial to their success. Why not guar- them to effectively share source code software viruses. Some are merely reck-
management, and as antee interoperability by insisting on and ideas. The network of developers less, some have criminal intent, but all
an XML architect at a single manufacturer, a fax machine is connected through Java, not through are destructive. J2EE provides a system
Wind River Systems. monopoly? compiled bytecode. designed from the ground up for se-
Ted received his PhD The reasons against this have been Less abstract is the network of curity and is deployable on a substrate
in mathematics in 1996 repeatedly established: an absence middleware, virtual machine, and op- that is robust through its diversity. The
from Emory University in of competition leads to lower quality, erating system suppliers. Once again, foundation of the alternative is well
Atlanta, Georgia. higher prices, a lack of innovation, and the free market demands that this be traveled by worms. This too serves as a
a vulnerable system. The free mar- a diverse collection. J2EE, through lesson that the network effect must be
ted.goddard@icesoft.com ket demands a diversity of suppliers, its focus on portability, provides an approached wisely.

66 August 2004 www.SYS-CON.com/JDJ


SPEND LESS TIME PROBLEM SOLVING… AND MORE TIME DEVELOPING APPLICATIONS.

PerformaSure — a system-wide performance


diagnostic tool for multi-tiered J2EE applications Join The Thousands of Companies Improving Java Application
running in test or production environments.
Performance with Quest Software.

Whether it’s a memory leak or other performance issues,

Quest Software’s award-winning Java products — including

JProbe® and PerformaSure™ — help you spend less time trouble-


JProbe — a performance tuning toolkit
for Java developers. shooting and more time on the things that matter. Quest’s Java

tools will identify and diagnose a problem all the way down to

the line of code, so you no longer have to waste time pointing

fingers or guessing where the problem lies. Maximize your

team’s productivity with Quest Software by downloading a free

eval today from http://www.quest.com/jdj.


© 2004 Quest Software Inc., Irvine, CA 92618 Tel: 949.754.8000 Fax: 949.754.8999

You might also like